fix(parser)!: limit filter length and nesting depth by default - #135
Merged
Merged
Conversation
pdevito3
force-pushed
the
fm/qk-breaking-prs-2
branch
from
October 1, 2026 21:33
7fc26d9 to
eed243a
Compare
v1.14.2 parsed a filter of any length and any nesting depth. A filter with a few thousand nested parentheses overflowed the call stack and stopped the host process. A catch block cannot stop a stack overflow. At depth 1000, one parse took more than 20 seconds of CPU. DefaultMaxInputLength is 5000 again and DefaultMaxNestingDepth is 32 again. MaxInputLength and MaxNestingDepth stay as settings, so an app can raise or lower each limit. BREAKING CHANGE: a filter longer than 5000 characters throws QueryKitInputLengthExceededException, and a filter with more than 32 levels of parentheses throws QueryKitNestingDepthExceededException. v1.14.2 parsed both. To keep the old behavior, set MaxInputLength and MaxNestingDepth to int.MaxValue.
…he default MaxInputLength
pdevito3
force-pushed
the
fm/qk-breaking-prs-2
branch
from
October 2, 2026 19:54
eed243a to
d2bb575
Compare
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.
For later consideration in a major version. Do not merge now. #134 turned these limits off by default to keep v1.x compatible with v1.14.2 (restore commit
42866b9). This PR turns them on by default again. It re-applies the default part ofde350f7(#109). The captain decides on this PR separately.Summary
MaxInputLengthandMaxNestingDepthstay as settings. An app can raise each limit, lower it, or set it toint.MaxValueto turn it off.v1.14.2 behavior (and main)
The parser accepts a filter of any length and any nesting depth.
New behavior
QueryKitInputLengthExceededException.QueryKitNestingDepthExceededException.QueryKitException. An app that mapsQueryKitExceptionto HTTP 400 returns 400.(inside a quoted value does not count.Example
x => (x.Age > 1).QueryKitNestingDepthExceededException, "depth of 33 ... maximum allowed depth of 32".Another input that v1.14.2 accepts and this PR rejects:
Id ^^ [...]with 140 GUIDs (5606 characters).Security risk on v1.14.2
Stack overflow.and exit code 134. Acatchblock cannot stop a stack overflow in .NET.QueryKitException, and the process keeps running.Justification
Most apps pass a filter string from a client to QueryKit without a length check. With no default limit, each of these apps has a denial of service hole that one request can use. A safe default protects the apps that do not know about the risk. An app with long in-lists or deep generated filters can raise the limits in one setting.
Migration
To keep the v1.14.2 behavior, turn the limits off:
README
The Parse Limits section gives the
5000and32defaults again. It also tells how to turn a limit off.Tests
These tests come back from main before #134:
ParseLimitsTests.filter_over_33_nesting_levels_parses_by_default->filter_over_default_nesting_depth_throwsParseLimitsTests.filter_over_5000_characters_parses_by_default->filter_over_default_input_length_throwsParseLimitsTests.configuration_that_implements_only_the_interface_has_no_limits->configuration_that_implements_only_the_interface_uses_the_default_limitsquoted_value_with_33_parentheses_parses_by_defaultstays, because a(inside a quoted value does not count on main.deep_filter_with_quoted_close_parentheses_throws_instead_of_overflowing_the_stacknow setsMaxInputLength = int.MaxValue. Its input is longer than 5000 characters, and the test is about the depth limit.dotnet test: 470 unit tests and 297 Postgres integration tests (Testcontainers) pass, 0 failures.Rebase on main
This branch is rebased on current main. Main now counts the nesting depth in the grammar (#157). This PR changes only the two default values, their doc comments, and the README text for the defaults.