Injection prevention

API Injection Prevention: Inputs, Queries and Output

Published: 19 September 2026

A constrained API contract helps clients, but injection prevention depends on how the server uses each value.

Follow each untrusted value to its sink

API injection prevention starts by tracing request values beyond the first validator. A path ID, search string, filter object, file name, or webhook field may reach a SQL query, document database, shell command, template, or browser-rendered response. The danger depends on how the value is used, not on whether the API is REST or GraphQL. Map the value's path and identify where data could be interpreted as syntax.

Treat headers and upstream service responses as untrusted too. An attacker may control a webhook payload or a field copied from a partner API. Normalise and validate inputs at the boundary, then use safe APIs at each sink. Validation is useful for domain rules; it cannot make string-built SQL or shell commands safe by itself.

Parameterise database access

For SQL, bind values as parameters rather than concatenating them into query text. Verify that the database driver actually supports binding for the query being built. Dynamic column names, sort directions, and table names usually cannot be treated as ordinary value parameters; choose them from a fixed server-side allowlist. Reject unexpected keys rather than interpolating arbitrary client input.

For document databases, validate the shape of filter objects and forbid operator keys where clients should supply scalar values. A JSON body can carry structures such as comparison operators that change a query's meaning. Do not pass a request object straight into a find or update call. Construct the query from explicitly permitted fields and types, and test nested objects, arrays, and unexpected keys.

Define useful OpenAPI constraints

Document required fields, data types, lengths, enumerations, numeric bounds, and accepted formats. A transfer amount should not accept a free-form string, and a sort order should have named choices. These constraints help clients and allow contract checks to highlight broad schemas. Keep them consistent with server validation; a strict document paired with a permissive service gives false confidence.

APISAST can flag request bodies that lack validation constraints in an OpenAPI or Swagger file. It cannot inspect a prepared statement, a NoSQL query builder, a template renderer, or command invocation. Treat the finding as a prompt to review the implementation. Conversely, a well-constrained schema is not evidence that injection is impossible in a downstream component.

Protect commands, URLs and templates

Avoid invoking a shell when a library or direct process API can perform the task. If a command is unavoidable, pass fixed executable and option arguments separately, apply an allowlist to user-selected values, and limit filesystem and network privileges. Never rely on shell escaping as the sole defence. Test filenames beginning with dashes, control characters, long values, and encoding variations.

For URLs supplied to fetchers, validate scheme and destination and prevent calls into internal networks; that is an SSRF concern as well as an input concern. For HTML rendered from API data, use context-appropriate output encoding and safe templating. JSON transport does not stop cross-site scripting when a browser later inserts a field into HTML. Avoid promising that one sanitiser is safe for every context.

Design tests around the interpreter boundary

Create positive cases for permitted values and negative cases for unexpected operators, quote characters, encodings, and oversized input. The expected result is a controlled validation error or a harmless literal value, never a query error, extra record, or executed command. Use test data that makes unintended broad matches visible. Run tests at the service boundary, not only against a validator helper.

Review error responses for leaked SQL text, stack traces, and file paths. A detailed database exception can reveal a table name or query structure even if injection does not succeed. Return a stable client error and record a correlation ID; keep diagnostic details in restricted logs. Add a regression test whenever an injection bug is fixed, including the exact sink that failed. Probe a controlled environment with synthetic records so a test cannot expose production data.

Keep the defence maintainable

Code review should ask where each request value enters a query or interpreter and whether a safe API is used. Prefer shared data-access helpers that enforce parameterisation and typed filters, but do not hide broad raw-query escape hatches in them. Review new integrations and report builders because injection often reappears outside the primary CRUD endpoints.

Separate transport validation from authorization. A correctly typed account ID may still belong to another user, and a safe query may still return too many rows. Combine input constraints with object-level permission checks, output minimisation, and limits on expensive searches. The result is a testable chain of controls rather than a single “sanitised” checkbox.

Worked example: a search filter

Suppose GET /orders accepts status and sort. Define status as one of pending, paid, or cancelled, and sort as createdAt or total. The server maps those names to fixed query fragments and binds any scalar values. It never copies the raw sort string into an ORDER BY clause. The OpenAPI document should expose the same accepted choices so clients cannot assume arbitrary expressions are supported.

Test status with an unexpected object instead of a string, a quote-containing value, and an operator-like key. Confirm that the service returns a controlled 400 and that the database query remains constrained to the caller's tenant. Test a valid status with an account ID from another tenant as well. Injection prevention and object authorization are independent: a perfectly parameterised query can still leak another account if its access predicate is missing.

Review escaping in the output context

An API may store a user-supplied display name safely and later render it in a browser, email, PDF, or log viewer. Each destination interprets text differently. Encode at the point of output for that context, and avoid marking untrusted content as trusted HTML in templates. A JSON response with a script-like string is usually just data; the XSS risk appears when a consumer inserts that value into executable markup.

Include downstream clients in the test plan. Render an intentionally hostile name in the actual web interface and support dashboard, and confirm that it appears as text. Check exports and notification templates too. This prevents the API team from declaring the flow safe solely because the server returned the correct Content-Type or escaped one field in one response.

Continue the work

Use these guides to put the checks into your API review process:

Primary reference: OWASP SQL Injection Prevention Cheat Sheet.

APISAST reviews OpenAPI and Swagger contracts for documented design signals. Confirm authorization, enforcement, performance, and abuse controls against a running service.

More API security guides