The Shifting Landscape
Injection attacks ranked first in the OWASP API Security Top 10 for years, and for good reason. SQL injection via API parameters, NoSQL injection in MongoDB queries, command injection through improperly validated inputs β these are well-documented, widely exploited, and still present in a significant fraction of production APIs. But the distribution of injection vectors has shifted dramatically as application architectures have changed.
Modern applications are predominantly SPA-with-API architectures. The server renders no HTML β it serves data as JSON. This has two security consequences: it reduces the traditional HTML-injection surface (since there is no server-side template to inject into) while simultaneously creating new cross-site attack surfaces (since the SPA JavaScript rendering layer now controls how API-returned data is presented to users).
The architecture shift changes the vulnerability distribution: In a server-rendered application, SQL injection is the primary risk in the data layer, and XSS is the primary risk in the presentation layer. In an API-driven SPA, both risks are in the API layer β injection attacks target the data processing, and cross-site attacks target how the JavaScript client renders API responses.
Modern API Injection
The canonical SQL injection in a URL query string is well understood and largely caught by WAFs and SAST. The injection variants that are underdetected in 2026 are:
JSON Body Injection
Injection payloads in JSON request bodies bypass many signature-based WAF rules because the payloads are not URL-encoded in the way traditional injection scanners expect. A NoSQL injection in a MongoDB query that goes through a JSON body looks like: {"username": {"$gt": ""}} β no SQL-like operators, no quote injection, just a JSON object with a MongoDB query operator. Many WAF rules do not inspect JSON bodies with the same depth as URL parameters.
HTTP Header Injection
API endpoints that reflect header values into responses, logs, or downstream service calls are vulnerable to header injection. Common targets: X-Forwarded-For reflected into audit logs creates log injection; User-Agent values stored in databases without sanitisation create injection into any downstream SQL queries; custom headers passed to backend services create injection into those services' processing.
GraphQL Injection
GraphQL resolvers that construct queries by concatenating user-controlled field names or arguments are susceptible to injection into whatever data store the resolver uses. The mutation-based and introspection-enabled nature of many GraphQL APIs also creates secondary risks: full schema exposure through introspection (revealing the complete data model and operations available) and deeply nested query attacks (extremely nested queries that cause exponential computational load).
The Cross-Site Surge
Cross-site scripting via APIs has increased substantially as a proportion of API attacks because the storage and delivery model of SPA applications creates more persistent XSS opportunities. Stored XSS payloads stored in an API backend are served to every client that retrieves that data β the blast radius of a single stored injection is every user who views the affected content, rather than just the user who was socially engineered into clicking a link.
APIs that return user-controlled content for direct DOM insertion in JavaScript clients without sanitisation are the primary surface. The typical pattern: an API endpoint returns a user's profile, the JavaScript client renders innerHtml = response.bio, and any HTML tags in the bio field execute in the browser. The API did not validate that the bio is safe to render as HTML; the client did not sanitise before rendering. Both failures are common.
CSRF against API endpoints remains relevant despite widespread adoption of CORS policies. API endpoints that rely solely on CORS for CSRF protection β without a CSRF token or SameSite cookie attribute β remain vulnerable to CSRF from same-site subdomains or via content-type manipulation that bypasses CORS preflight requirements.
The Detection Gap
Traditional WAF rules focus on URL parameter inspection, SQL pattern matching, and HTML tag detection. They underperform on: JSON body inspection for NoSQL operators, GraphQL query complexity analysis, response body XSS payload detection (the payload is in the stored data, not the request), and header injection patterns in custom headers.
DAST tools that test for injection by fuzzing URL parameters miss JSON body injection entirely unless explicitly configured for it. API security scanners that do not perform authenticated, stateful testing cannot identify stored XSS payloads β finding stored XSS requires both the write operation (the injection) and the read operation (the retrieval that executes the payload) to be included in the test scope.
GraphQL as an Attack Surface
GraphQL has become a significant attack surface for several reasons that go beyond injection. Introspection β enabled by default in most GraphQL servers β exposes the complete schema, allowing an attacker to enumerate all available types, queries, and mutations without any prior knowledge of the API design. This is reconnaissance at no cost.
Batch query attacks abuse GraphQL's ability to execute multiple operations in a single request. Authentication rate limiting is typically applied per request; a single GraphQL request containing 1000 login mutations with different credential combinations bypasses per-request rate limits entirely. Alias-based bypass (using different aliases for the same field to execute it multiple times in one request) has the same effect.
Mitigations
- Use parameterised queries for all data store operations: This applies to SQL, NoSQL, and graph databases. Do not build queries by concatenating user input at any layer, including GraphQL resolvers.
- Validate and sanitise all user-controlled content before storage: The correct place to validate content that will be rendered as HTML is at write time, not at read time. Stored XSS payloads that reach your vector store or relational database are already a failure mode β prevent them at ingestion.
- Sanitise at the rendering layer too: Use a context-aware sanitiser (DOMPurify for DOM insertion, HTML encoding for server-side rendering contexts) at every point where API-returned data is rendered. Defense in depth applies here β both storage-time and render-time sanitisation.
- Disable GraphQL introspection in production: Introspection is a development-time tool. Disable it in production environments where you do not need external parties to explore your schema. It provides no value to legitimate clients and significant value to attackers.
- Implement GraphQL query depth and complexity limits: Reject queries that exceed a configured depth (typically 5-10 levels) and complexity score. This prevents both denial-of-service through deeply nested queries and unbounded data extraction through highly nested traversals.
- Apply CSRF protection that does not rely solely on CORS: Use
SameSite=StrictorSameSite=Laxon session cookies and require explicit CSRF tokens for state-changing operations. CORS policies do not protect against CSRF from same-site origins. - Configure WAF rules to inspect JSON bodies: Ensure your WAF or API gateway applies injection detection rules to JSON request bodies, not just URL parameters and query strings. Test your WAF configuration against JSON-body injection payloads specifically.
The API security problem in 2026 is not that the vulnerability classes are new β SQL injection is decades old, XSS is well-understood β it is that the architectures that carry these vulnerabilities have changed while many security controls were not updated to match. The gap between the threat landscape and the WAF rule set you deployed in 2022 is worth auditing.