Skip to content

Cap recursion depth and input length in SCIM Path and FilterExpression parsers (FireWatch 6e560c31)#138

Merged
himanshusainig merged 2 commits into
AzureAD:masterfrom
Jordancle:jordanle/FireWatch-ParserDepthCaps-only
Jun 17, 2026
Merged

Cap recursion depth and input length in SCIM Path and FilterExpression parsers (FireWatch 6e560c31)#138
himanshusainig merged 2 commits into
AzureAD:masterfrom
Jordancle:jordanle/FireWatch-ParserDepthCaps-only

Conversation

@Jordancle

@Jordancle Jordancle commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

FireWatch finding: 6e560c31 · IMPORTANT · CWE-674: Uncontrolled Recursion

Summary

Both Path.TryParse and FilterExpression(string,int,int) are recursive-descent parsers that process attacker-supplied SCIM query strings. With no depth or length guard, ~8000+ dot-separated segments (Path) or logical clauses (FilterExpression) trigger a non-catchable StackOverflowException that terminates the process — a DoS that crashes any SCIM endpoint.

Fix

Adds two defensive caps to each parser:

Cap Value Purpose
MaxPathLengthChars / MaxFilterLengthChars 16,384 Reject oversized input at top level
MaxRecursionDepth 32 Bound stack growth per recursive call

Real SCIM paths are <200 chars with <5 segments; real filters are <2KB with <20 clauses. Caps leave 80x+ headroom.

Files Changed

  • Protocol/Path.cs — public TryParse delegates to private depth-tracking overload
  • Protocol/FilterExpression.cs — existing ctor delegates to new depth-tracking ctor

Comprehensive tests for this fix live in the downstream SyncFabric-SCIM-Tools port (PR 16038663).

…n parsers (FireWatch 6e560c31)

Both Path.TryParse and the FilterExpression(string,int,int) chain are hand-rolled
recursive-descent parsers that process attacker-supplied strings. With no depth,
length, or clause-count guard, an input with ~8000+ dot-separators (Path) or
~8000+ logical clauses (FilterExpression) triggers a StackOverflowException,
which is non-catchable in .NET and terminates the process — a DoS that crashes
any SCIM endpoint validating /Users?filter= or PATCH path parameters.

FireWatch finding 6e560c31, IMPORTANT, PARTIALLY_EXPLOITABLE.

Adds two defensive caps to each parser:
  * MaxPathLengthChars / MaxFilterLengthChars (16384) - input cap, top-level only
  * MaxRecursionDepth (32) - per-recursion cap, defense in depth

Real SCIM paths are <200 chars with <5 segments; real filters are <2KB with <20
clauses; the caps leave 80x+ headroom for legitimate use while bounding the
worst-case recursion depth to a trivial fraction of the .NET stack.

Implementation:
  * Path.TryParse now has a public (depth=0) and private (depth+1 recursive)
    overload. Returns false at top-level on overlong input or when depth exceeds
    the recursion cap (consistent with existing TryParse return-value semantics).
  * FilterExpression gains a (text, group, level, depth) private constructor;
    the existing (text, group, level) ctor delegates with depth=0. Length/depth
    cap violations throw ArgumentException, which Filter.TryParse already
    catches and returns false.

No tests in this repo (SCIMReferenceCode has no test project per its
sample-only charter); comprehensive tests for the same fix are provided in the
downstream port to internal SyncFabric-SCIM-Tools.

FireWatch finding: https://firewatch-pilot-fd-atb3ceg5egfxc9gg.b02.azurefd.net/Services/fbfae0f8-2ef1-47f4-94e5-029d635c2081/scimreferencecode/6e560c31-8f32-4d36-aa0c-92a5e1d621f4

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Jordancle

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree [company="Microsoft"]

@Jordancle

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree company="Microsoft"

Comment thread Microsoft.SystemForCrossDomainIdentityManagement/Protocol/Path.cs Outdated
Comment thread Microsoft.SystemForCrossDomainIdentityManagement/Protocol/FilterExpression.cs Outdated
Comment thread Microsoft.SystemForCrossDomainIdentityManagement/Protocol/FilterExpression.cs Outdated
Comment thread Microsoft.SystemForCrossDomainIdentityManagement/Protocol/Path.cs Outdated
Comment thread Microsoft.SystemForCrossDomainIdentityManagement/Protocol/Path.cs Outdated
- Fix off-by-one: depth > MaxRecursionDepth -> depth >= MaxRecursionDepth
  (both Path.cs and FilterExpression.cs)
- Copy depth field in FilterExpression copy constructor to prevent bypass
- Fix misleading comment in Path.cs: recursion is for bracket filter
  expressions, not dot-separated segments

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@himanshusainig himanshusainig merged commit 61a9e36 into AzureAD:master Jun 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants