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.
Low because GraphQL depth attacks require a valid query and authenticated access, but the resource cost of deeply nested queries scales exponentially with depth.
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.
ID: api-security.abuse-prevention.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')
}
}
}
})