no-graphql-injection
Detects GraphQL injection vulnerabilities and DoS attacks
CWE: CWE-74
OWASP Mobile: OWASP Mobile Top 10
Detects GraphQL injection vulnerabilities and DoS attacks. This rule is part of eslint-plugin-secure-coding and provides LLM-optimized error messages.
πΌ This rule is set to error in the recommended config.
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-943 (GraphQL Injection), CWE-400 (DoS) |
| Severity | Critical |
| Auto-Fix | π‘ Suggestions available |
| Category | Security |
Value & investment case
Why this rule pays for itself. Framework:
cicd-impact/philosophy.md.
| Dimension | Value |
|---|---|
| CWE | CWE-943 β Improper Neutralization in Data Query Logic + CWE-400 (DoS) |
| Feedback-loop tier | Editor / pre-commit (sub-second) β cheapest layer per the feedback-loop hierarchy |
| Defensive-layer leverage | ~10Γ cheaper than unit-test Β· ~1,000Γ cheaper than production rollback Β· 10,000+Γ cheaper than customer disclosure (cost-ratio anchors) |
| Niche relevance | Critical: B2B SaaS (GraphQL-heavy modern API surface), fintech Β· High: marketplaces, infra/devtools, healthtech Β· Medium: B2C |
| Investor-frame impact | GraphQL injection β unauthorized data access across multiple tenants in a B2B SaaS = single-incident multi-customer disclosure cycle. Catch at lint-time prevents the breach class entirely. |
Read also: philosophy.md Β§investor-frame Β· niche-presets.json Β· analyzer-evaluation-framework.md
Vulnerability and Risk
Vulnerability: GraphQL injection arises when backend queries are constructed dynamically using user inputs via string concatenation or interpolation, instead of using standard GraphQL variables.
Risk: Attackers can manipulate the query structure to bypass permissions, access unauthorized data fields, perform Denial of Service (DoS) via nested queries, or execute batching attacks to overload the server.
Rule Details
GraphQL injection occurs when user input is improperly inserted into GraphQL queries, allowing attackers to:
- Read or modify unauthorized data
- Perform DoS attacks with complex/nested queries
- Extract schema information via introspection
What counts as a GraphQL document
A template literal is not a GraphQL query just because it has braces in it. Two requirements were tightened in 2026-07 after a 1,470-file corpus run (webpack, lodash, eslint-plugin-import, two NestJS boilerplates) produced 41 findings at CVSS 9.8, every one of them an ordinary message or code-generation string:
- Operation and schema keywords must start a line. GraphQL declares
query,mutation,subscription,fragment,type,interface,enum,scalarandinputat the start of a line; English mentions them mid-clause. Matching them anywhere in the text turned`Please specify --type ${a} or ${b}`and`Invalid type ${t}`into GraphQL-injection findings. A schema keyword additionally requires the text to contain a{β a type definition has a body. - A bare selection set must BE the whole string. Nested braces inside a
larger message are not a selection set. Requiring the trimmed text to start
with
{and end with}is what stops webpack's`resolve.fallback: { "${request}": require.resolve("${alias}") }`from matching.
String concatenations are evaluated on their reassembled static string
value, not on sourceCode.getText() β otherwise the JS quoting ("query {β¦)
sits in front of the query and defeats the start-of-line test.
Why This Matters
| Issue | Impact | Solution |
|---|---|---|
| π Injection | Unauthorized data access | Use GraphQL variables |
| π₯ DoS | Service unavailability | Limit query depth/complexity |
| π Info Leak | Schema exposure | Disable introspection in production |
Examples
β Incorrect
// String interpolation in GraphQL query
const query = `
query {
user(id: "${userId}") {
name
email
}
}
`;
// Introspection query in production
const introspect = `{ __schema { types { name } } }`;
// String concatenation
const searchQuery = 'query { users(name: "' + userInput + '") { id } }';β Correct
// Use GraphQL variables
const query = gql`
query GetUser($userId: ID!) {
user(id: $userId) {
name
email
}
}
`;
await client.query({ query, variables: { userId } });
// Use query builders
import { buildQuery } from 'graphql-tools';
const safeQuery = buildQuery({ user: { id: userId } });Configuration
{
rules: {
'secure-coding/no-graphql-injection': ['error', {
allowIntrospection: false, // Disable introspection detection
maxQueryDepth: 10, // Maximum query nesting depth
trustedGraphqlLibraries: ['graphql', 'apollo-server', 'graphql-tools'],
validationFunctions: ['validate', 'sanitize']
}]
}
}Options
| Option | Type | Default | Description |
|---|---|---|---|
allowIntrospection | boolean | false | Allow introspection queries |
maxQueryDepth | number | 10 | Maximum query nesting depth before reporting a DoS risk |
trustedGraphqlLibraries | string[] | ["graphql","apollo-server","graphql-tools","graphql-tag"] | GraphQL libraries recognised as query builders |
validationFunctions | string[] | ["validate","sanitize","isValid","assertValid"] | Function names that count as query validation |
safeTemplateLiteralCallers | string[] | [] | Additional callers where template literals are never GraphQL. Format: object.method or ClassName. |
trustedSanitizers | string[] | [] | Additional function names to consider as GraphQL sanitizers |
trustedAnnotations | string[] | [] | Additional JSDoc annotations to consider as safe markers |
strictMode | boolean | false | Disable all false positive detection (strict mode) |
Error Message Format
π CWE-943 OWASP:A03-Injection CVSS:8.6 | GraphQL Injection detected | CRITICAL [SOC2,PCI-DSS]
Fix: Use GraphQL variables instead of string interpolation | https://owasp.org/...Known False Negatives
The following patterns are not detected due to static analysis limitations:
Query from Variable
Why: Query strings from variables not traced.
// β NOT DETECTED - Query from variable
const query = `SELECT * FROM users WHERE id = ${userId}`;
db.execute(query);Mitigation: Always use parameterized queries.
Custom Query Builders
Why: Custom ORM/query builders not recognized.
// β NOT DETECTED - Custom builder
customQuery.where(userInput).execute();Mitigation: Review all query builder patterns.
Template Engines
Why: Template-based queries not analyzed.
// β NOT DETECTED - Template
executeTemplate('query.sql', { userId });Mitigation: Validate all template variables.
Further Reading
- GraphQL Security - Official security guide
- Apollo Security Checklist - Production security
- CWE-943 - GraphQL injection documentation
Related Rules
no-sql-injection- SQL injection preventiondetect-eval-with-expression- Code injection prevention
Did this rule catch something? Star the repo to get new CWE coverage as we ship it β or follow the AI-code-security benchmarks behind these rules.