Bound GraphQL nested-filter recursion depth - #3776
Open
Souvik Ghosh (souvikghosh04) wants to merge 1 commit into
Open
Bound GraphQL nested-filter recursion depth#3776Souvik Ghosh (souvikghosh04) wants to merge 1 commit into
Souvik Ghosh (souvikghosh04) wants to merge 1 commit into
Conversation
Thread a nesting-level counter through the recursive GraphQL filter parser and reject filters whose relationship nesting exceeds runtime.graphql.depth-limit (when set and stricter) or a hardcoded safety ceiling. Prevents nested-filter depth-bomb amplification into deeply correlated EXISTS subqueries, which the HotChocolate execution-depth rule does not cover.
Souvik Ghosh (souvikghosh04)
marked this pull request as ready for review
August 18, 2026 06:08
Copilot started reviewing on behalf of
Souvik Ghosh (souvikghosh04)
August 18, 2026 06:09
View session
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a guardrail to the GraphQL filter parser to cap relationship-nesting depth in filter:{ rel:{ rel:{ ... }}} scenarios, preventing small requests from expanding into very expensive nested query plans.
Changes:
- Introduces a maximum nested-filter depth (hard ceiling of 20) and enforces it during recursive filter parsing, optionally honoring a stricter
runtime.graphql.depth-limit. - Threads a
nestingLevelcounter through recursive parsing paths (Parse,HandleNestedFilterForSql/Cosmos,ParseAndOr) and returns HTTP 400 on violations. - Adds unit tests validating effective limit selection and the enforcement helper.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/Core/Models/GraphQLFilterParsers.cs |
Adds max-depth resolution/enforcement and propagates nesting depth through recursive parsing. |
src/Service.Tests/UnitTests/GraphQLFilterParserUnitTests.cs |
Adds unit tests for depth-limit resolution and guard enforcement behavior. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
89
to
+91
| List<ObjectFieldNode> fields, | ||
| BaseQueryStructure queryStructure) | ||
| BaseQueryStructure queryStructure, | ||
| int nestingLevel = 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bounds the relationship-nesting depth of GraphQL filter arguments (e.g.
filter:{rel:{rel:{...}}}). Deeply nested filters expand into correlatedEXISTSsubqueries that the HotChocolate execution-depth rule does not cover, so a small deeply-nested request could amplify into a very expensive query.Change
GQLFilterParser.Parse/HandleNestedFilter*/ParseAndOr).runtime.graphql.depth-limit(when set and stricter) or a hardcoded safety ceiling (20) with an HTTP 400.Parseparameter is optional; external callers are unchanged.Tests
depth-limit = -1(unlimited) case still capped at the ceiling.Note
Filters nesting beyond 20 relationship levels now return 400 instead of executing; this is far above typical usage.