Should Keystone enforce GraphQL query depth limits by default?
Context
Multiple independent security researchers (myself and @nedlir) have independently identified that Keystone's GraphQL API has no query depth limiting, complexity analysis, or cost budgeting.
A single unauthenticated request with a deeply-nested circular relationship query (e.g. users → posts → author → posts → author → ...) triggers exponential database queries. In local testing against a SQLite database with 6 total records, a depth-16 query caused a 38-second server hang.
This is classified as CWE-400: Uncontrolled Resource Consumption.
What other GraphQL frameworks do
| Framework | Default depth limit | Complexity analysis |
|---|---|---|
| Hasura | Yes (built-in) | Yes |
| PostGraphile | Configurable | Yes (cost analysis) |
| graphql-ruby | max_depth + max_complexity |
Yes |
| Lighthouse (Laravel) | Yes (configurable) | Yes |
| Keystone | None | None |
Reproduction
Any Keystone project with bidirectional relationships (the standard pattern):
# No authentication required (with allowAll access)
{
users {
posts {
author {
posts {
author {
posts {
author {
posts {
author { id }
}
}
}
}
}
}
}
}
}Measured response times (SQLite, 1 user + 5 posts + 15 comments):
| Depth | Time |
|---|---|
| 12 | 0.9s |
| 14 | 4.2s |
| 16 | 38s (timeout) |
Proposal
Add a default query depth limit (e.g. 10) using graphql-depth-limit or equivalent, with a configuration option:
export default config({
graphql: {
maxDepth: 10, // default, configurable
},
})Questions
- Should Keystone ship with a default query depth limit?
- Should this be treated as a security advisory or a hardening improvement?
- What default depth limit would be appropriate?
cc @nedlir @dcousens
Source: keystonejs/keystone