GraphQL Missing Depth/Complexity Limit
ID |
graphql_missing_depth_limit |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Family |
API4:2023 - Unrestricted Resource Consumption |
CWE |
CWE-770 |
Resource |
configuration |
Language |
any |
Description
Fires once per GraphQL service when the project constructs a GraphQL server but shows no evidence of a query depth or complexity limiter — graphql-depth-limit, graphql-query-complexity, graphql-validation-complexity, GraphQL Armor, graphql-java MaxQueryDepthInstrumentation / MaxQueryComplexityInstrumentation, Strawberry QueryDepthLimiter, Hot Chocolate AddMaxExecutionDepthRule, or an explicit maxDepth/max_depth configuration.
Evidence patterns are deliberately generous — an unrelated match only silences the finding — and gateway/proxy-level enforcement is not visible to static analysis, so the finding is advisory until reviewed against the deployment. SDL-only repositories are not flagged.
Rationale
Unlike REST, a single GraphQL request describes an arbitrary computation over the graph. Without a depth/complexity ceiling, deeply-nested queries, alias fan-out, and circular fragments over connected types (user → friends → friends → …) let one request multiply into unbounded resolver and database work — the GraphQL flavor of OWASP API4:2023, Unrestricted Resource Consumption (CWE-770). This is the standard vector for GraphQL denial-of-service and denial-of-wallet, and it also amplifies enumeration attacks that per-request rate limits would otherwise slow down.
Remediation
Add a query depth and/or complexity ceiling appropriate to your stack:
-
GraphQL.js / Apollo:
validationRules: [depthLimit(8)]fromgraphql-depth-limit, orgraphql-query-complexitywith a cost estimator -
GraphQL Armor: enables
maxDepth/cost guards out of the box -
graphql-java:
new MaxQueryDepthInstrumentation(10)/MaxQueryComplexityInstrumentation -
Strawberry:
extensions=[QueryDepthLimiter(max_depth=10)] -
Hot Chocolate:
.AddMaxExecutionDepthRule(10)
Pick the limit from your deepest legitimate query plus margin, and monitor/alert on rejected queries to catch probing.