fix(filter)!: apply PreventFilter and PreventSort to every property path - #136
Merged
Merged
Conversation
This was referenced Oct 1, 2026
pdevito3
force-pushed
the
fm/qk-breaking-prevent-bypass
branch
from
October 1, 2026 21:35
fc9011c to
a62bbeb
Compare
PreventFilter was checked only for a left-side member, by its name in the exact case after the query-name rewrite. Arithmetic, the right side of a comparison, a property list in another case, derived properties, and custom operations skipped the check. PreventSort was checked by the typed path in the exact case. A caller could learn the value of a hidden field one comparison at a time. The parser now resolves each property reference and applies the prevent settings in each of these places. A prevented clause follows IgnoredClauseBehavior, and a prevented sort is skipped. Arithmetic does not apply MaxPropertyDepth in this change. BREAKING CHANGE: a filter or sort that reaches a property with PreventFilter or PreventSort through arithmetic, the right side, a property list, another letter case, the member name of a property with a query name, a derived property, or a custom operation no longer filters or sorts by that property. The clause follows IgnoredClauseBehavior, and the sort is skipped.
pdevito3
force-pushed
the
fm/qk-breaking-prevent-bypass
branch
from
October 3, 2026 11:42
a62bbeb to
a571d97
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.
Summary
PropertyResolverand checksPreventFilterin arithmetic, on the right side, in a property list, and on the left side. The lookup ignores the letter case.PreventFilterare checked too.SortParserchecksPreventSorton the resolved member. Another letter case, or the member name of a property with a query name, is also checked. A derived property withPreventSortis checked too.reference.Path, not from the raw text. As a result, the checked property is always the property that QueryKit compares or sorts by.IgnoredClauseBehavior(removed by default on v2). A prevented sort is skipped.v1.14.2 behavior
PreventFilterwas checked only for a left-side member, by its name in the exact case.PreventSortwas checked by the typed path in the exact case. A caller could filter or sort by a prevented property in six ways:(Age + 0) > 30AgePreventFilterAgeFirstName == SecretSecretPreventFilterx => (x.FirstName == x.Secret)(secret, FirstName) @=* "s"SecretPreventFilterSecretFirstNamesecret == "s"SecretPreventFilter, query namehiddenx => (x.Secret == "s")fullName == "Ann Lee"age descAgePreventSort, query nameyearsAgeA custom operation with
PreventFilterwas also still applied.Security risk on v1.14.2
With any of these bypasses, a caller can find the value of a hidden field one comparison at a time, for example
(Salary + 0) > 50000, then> 75000. A sort bypass shows the order of the hidden values.Migration
No setting brings back the old behavior. If a caller needs to filter by a property, remove
PreventFilterfrom it.Rebase on v2
MaxPropertyDepthcheck of fix(filter)!: apply MaxPropertyDepth to property paths in arithmetic #138 now share one walk,ResolveArithmeticProperties. It returnsnullfor a prevented property, and the parser then ignores the clause.ResolveWithoutDepthCheckis deleted, because arithmetic must obey the depth limit.Ingredients.name ascthrowsSortParsingException, not aNullReferenceException(fix(filter)!: resolve a child collection member in any case #139).Tests
PropertyResolverTests: the prevent tests from before fix: restore v1.14.2 behavior for every breaking change on main #134 come back, plusproperty_on_the_right_side_is_compared_by_its_resolved_path,sort_property_is_sorted_by_its_resolved_path, andsort_on_a_collection_member_path_throws_a_sort_parsing_exception.PropertyResolverTests(Postgres): the prevent tests from before fix: restore v1.14.2 behavior for every breaking change on main #134 come back.dotnet test: 517 unit tests and 321 Postgres integration tests pass.Part of #132.