GraphQL query depth limited
Why it matters
GraphQL's type system allows clients to construct arbitrarily nested queries — a feature designed for flexibility that becomes a denial-of-service vector without depth limiting. CWE-400 (Uncontrolled Resource Consumption) and OWASP API Security Top 10 2023 API4 (Unrestricted Resource Consumption) both apply. A deeply nested query like { author { posts { comments { author { posts { comments { ... } } } } } } } triggers exponential database joins with each additional level. Unlike REST, where resource boundaries are fixed in the URL, GraphQL puts the query structure in the client's hands. Depth limiting is a server-side control that caps the structural complexity a client can demand regardless of individual field costs.
Severity rationale
Low because GraphQL depth attacks require a valid query and authenticated access, but the resource cost of deeply nested queries scales exponentially with depth.
Remediation
Add a depth-limiting validation rule to your GraphQL server at startup. A limit of 7–10 levels covers most legitimate use cases while blocking exponential fan-out queries.
// src/lib/graphql/server.ts
import { createComplexityLimitRule } from 'graphql-validation-complexity'
import depthLimit from 'graphql-depth-limit'
const server = new ApolloServer({
schema,
validationRules: [
depthLimit(7), // reject queries deeper than 7 levels
createComplexityLimitRule(1000) // optional: cost-based limit
]
})
If you don't use Apollo, pass validationRules to graphql-js's validate() function before executing any query.
Detection
-
ID:
graphql-depth-limit -
Severity:
low -
What to look for: Enumerate every relevant item. For GraphQL APIs, check whether query depth limiting is implemented. This prevents deeply nested queries that could cause denial of service or expensive database operations.
-
Pass criteria: At least 1 of the following conditions is met. A query depth limit is enforced (typically 5-10 levels). Queries exceeding the depth limit are rejected.
-
Fail criteria: No query depth limit is implemented, allowing deeply nested queries.
-
Skip (N/A) when: The application does not use GraphQL.
-
Detail on fail:
"GraphQL has no query depth limit — attackers can craft deeply nested queries for DoS" -
Remediation: Implement depth limiting using graphql-depth-limit or equivalent:
import depthLimit from 'graphql-depth-limit' const server = new ApolloServer({ schema, plugins: { didResolveOperation: (ctx) => { const { request: { query } } = ctx const depth = getQueryDepth(query) if (depth > 10) { throw new Error('Query depth exceeds limit') } } } })
External references
- cwe · CWE-400 — Uncontrolled Resource Consumption
- cwe · CWE-1088 — Synchronous Access of Remote Resource without Timeout
- owasp:2023 · API4 — Unrestricted Resource Consumption
Taxons
History
- 2026-04-18·v1.0.0·Initial import from api-security·automated