Injection attacks are some of the oldest tricks in the book — and yet, decades later, they are still one of the most common ways APIs get broken into. I want to walk through what injection actually means, all the different flavors it comes in, and exactly how to stop it.
What Is an Injection Attack?
An injection attack happens when an API takes untrusted input from a client and passes it into an interpreter — a database, an operating system shell, a template engine, or another backend system — without properly separating the data from the commands. Because the interpreter can’t tell the difference between “this is just data” and “this is an instruction,” the attacker’s crafted input ends up being executed as a command.
I think of it like handing someone a note to read aloud, but the note secretly contains instructions like “and now open the safe.” If the reader can’t tell the difference between the message and a command, they’ll just follow it.
The Different Types of Injection (Expanded)
Injection isn’t just “SQL injection.” Let me walk through every major type relevant to APIs.
1. SQL Injection (SQLi)
The classic. If an API builds a SQL query by directly concatenating user input into a query string, an attacker can manipulate that query.
SELECT * FROM users WHERE username = '' AND password = ''
If the input for username is:
' OR '1'='1
The query becomes:
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = ''
This can bypass login entirely, dump entire tables, or in advanced cases (using techniques like UNION-based or blind SQL injection), extract the whole database one bit at a time.
2. NoSQL Injection
Databases like MongoDB use JSON-like query objects instead of SQL strings, but they are equally vulnerable if input isn’t sanitized. For example, sending:
{ "username": "admin", "password": { "$ne": null } }
Instead of a plain password string, some poorly written backends interpret $ne (not equal) as a MongoDB operator, effectively saying “match any password that is not null” — bypassing authentication completely.
3. Command Injection (OS Command Injection)
If an API takes user input and passes it into a system shell command — for example, a file-conversion API that runs a shell command using the uploaded filename — an attacker can inject additional shell commands.
filename = "report.pdf; rm -rf /"
If this gets passed unsanitized into a shell command, the attacker’s extra command executes on the server.
4. LDAP Injection
Similar concept, but targeting LDAP directory queries (often used in enterprise authentication systems). Malicious input can manipulate LDAP filter syntax to bypass authentication or extract directory data.
5. XML Injection / XXE (XML External Entity)
APIs that accept XML input can be tricked into parsing malicious external entities, potentially reading local files on the server or making the server send requests to internal systems (a form of Server-Side Request Forgery).
]>
&xxe;
6. Template Injection (Server-Side Template Injection, SSTI)
If user input is passed directly into a template engine (like Jinja2, Freemarker, or Twig) without proper escaping, attackers can inject template syntax that executes code on the server.
7. Cross-Site Scripting (XSS) via API Responses
While XSS is traditionally a frontend issue, APIs that store unsanitized user input and later serve it back to be rendered in a web page (a “stored XSS” scenario) are part of the injection family — the API is the delivery mechanism.
8. GraphQL Injection
GraphQL APIs, if not carefully validated, can be vulnerable to injection through deeply nested queries that manipulate underlying resolvers, or through unsanitized arguments passed into database queries behind the scenes.
9. Header Injection / CRLF Injection
Injecting carriage return and line feed characters (\r\n) into input that gets placed into HTTP headers, potentially allowing response splitting or header manipulation.
10. Log Injection
Injecting special characters or fake log entries into user input that later gets written directly into log files, potentially forging log records or breaking log parsing/monitoring tools.
11. Regular Expression Injection (leading to ReDoS)
Not exactly “code injection” in the classic sense, but user-controlled input passed into a regex pattern (instead of just being matched against one) can allow attackers to craft catastrophic backtracking patterns.
12. Deserialization Injection
When an API deserializes untrusted data (like a serialized Java object, Python pickle, or PHP object) without validation, attackers can craft malicious serialized payloads that execute arbitrary code when deserialized. This is sometimes classified separately as “Insecure Deserialization,” but it functions as an injection at its core — malicious data being interpreted as executable instructions.
Why Injection Still Happens in Modern APIs
- String concatenation instead of parameterized queries — building queries by gluing strings together.
- Trusting client input by default — assuming data from a mobile app or frontend is “already safe” because it came through the app’s UI.
- Mixing data and code in the same channel — the fundamental design flaw behind almost every injection type.
- Overly permissive parsers — accepting external entities in XML, or unsafe deserialization libraries, without restriction.
- Copy-pasted code from outdated tutorials that never accounted for security in the first place.
- Complex, multi-layered systems — an API might sanitize input for its own database call, but pass that same input untouched to another internal service that isn’t as careful.
How to Detect Injection Vulnerabilities
- Try classic SQLi payloads in every input field:
' OR '1'='1,admin'--,1; DROP TABLE users. - Test JSON-based NoSQL operators like
$ne,$gt,$regexin fields that expect plain strings. - Test file names, URLs, and any field that might be passed to a shell command with characters like
;,&&,|, backticks. - Send crafted XML payloads with external entity definitions if the API accepts XML.
- Check how special characters are handled in every input — apostrophes, quotes, angle brackets, backslashes.
- Look at error messages — a raw database error message leaking table/column names is a strong signal that injection may be possible.
- Test GraphQL introspection and nested queries for unusual behavior with crafted arguments.
- Fuzz all input fields, not just obvious ones like login forms — search bars, filters, and even HTTP headers can be injection points.
How to Prevent Injection Attacks
1. Always Use Parameterized Queries / Prepared Statements
Never build SQL (or NoSQL) queries by concatenating strings. Use parameterized queries so the database always treats user input strictly as data, never as part of the command structure.
// Safe pattern (conceptual)
query = "SELECT * FROM users WHERE username = ? AND password = ?"
execute(query, [username, password])
2. Use an ORM Correctly
Object-Relational Mapping tools (like SQLAlchemy, Sequelize, Hibernate) help avoid raw string queries — but they can still be misused if raw query methods are used carelessly. Always prefer their safe query-building methods.
3. Validate and Sanitize All Input
Enforce strict types, lengths, and formats for every input field using schema validation (like JSON Schema, or framework-native validators). Reject anything that doesn’t match the expected shape.
4. Avoid Shell Commands With User Input Entirely
Where possible, use language-native libraries instead of shelling out to OS commands. If you must use a shell command, use safe APIs that separate arguments properly instead of building a single command string.
5. Disable External Entities in XML Parsers
Configure your XML parser to disable DTDs and external entity resolution by default (most modern libraries allow this with a simple configuration flag).
6. Escape Output Properly for Templates
Use auto-escaping features built into modern template engines, and never manually build templates by injecting raw user input into template strings.
7. Avoid Insecure Deserialization
Never deserialize data from untrusted sources using formats that allow arbitrary object instantiation. Prefer safe, simple data formats like JSON with strict schema validation over native language serialization formats.
8. Apply Least Privilege to Database Accounts
Even if injection occurs, a database account with minimal permissions (no DROP, no access to unrelated tables) limits the damage an attacker can do.
9. Use a Web Application Firewall (WAF)
A WAF can catch and block many common injection payload patterns before they even reach your application — a good extra layer, though never a replacement for proper coding practices.
10. Keep Libraries and Frameworks Updated
Many injection-adjacent vulnerabilities (like deserialization flaws) get patched in library updates. Staying current closes known attack paths.
Business Impact of Injection
- Full database compromise — attackers can read, modify, or delete all data.
- Authentication bypass — logging in as any user, including admins, without knowing a password.
- Remote code execution — in the worst cases (command injection, deserialization, SSTI), attackers gain full control of the server.
- Regulatory and legal consequences — data breaches from injection attacks routinely trigger compliance violations and lawsuits.
Final Thoughts
Injection has been on security awareness lists for over twenty years, and it’s still relevant because the underlying mistake — mixing data and commands — is easy to make and easy to overlook, especially under deadline pressure. The fix is consistent across every type: never let raw, untrusted input be interpreted as code or commands. Treat every single input field as hostile until proven otherwise.