VYPR
High severity8.7GHSA Advisory· Published May 6, 2026· Updated May 19, 2026

scim_proton and kanidm_proto have an authenticated process abort via SCIM filter stack exhaustion

CVE-2026-46689

Description

Summary

A single unauthenticated GET to any /scim/v1/... endpoint with a ?filter= query string of a few thousand nested parentheses (≈ 4–12 KB) drives the recursive-descent PEG parser past the worker thread's stack guard page. Rust responds to stack overflow with std::process::abort() — the entire kanidmd process exits. The parse runs inside axum's Query extractor, before any handler body and therefore before any ACL check.

Details

The SCIM filter grammar recurses on ( and not ( with no depth bound.

**proto/src/scim_v1/mod.rs:263-433** — peg::parser! { grammar scimfilter() ... }:

// line 281
"not" separator()+ "(" e:parse() ")" { ScimFilter::Not(Box::new(e)) }
// line 293
"(" e:parse() ")" { e }

Both rules re-enter parse() without a depth counter.

**proto/src/scim_v1/mod.rs:442-447** — impl FromStr for ScimFilter calls scimfilter::parse(input) directly on the raw string with no length or depth pre-check.

**proto/src/scim_v1/mod.rs:80-81** — ScimEntryGetQuery.filter is #[serde_as(as = "Option")], so deserialising the query struct invokes ScimFilter::from_str on attacker bytes.

Unauthenticated reachability — nine handlers in server/core/src/https/v1_scim.rs (route table at lines 865-1029) take Query as an argument: /scim/v1/Entry, /scim/v1/Entry/{id}, /scim/v1/Person/{id}, /scim/v1/Application, /scim/v1/Application/{id}, /scim/v1/Class, /scim/v1/Attribute, /scim/v1/Message, /scim/v1/Message/{id}. The SCIM router is merged unconditionally for every server role (server/core/src/https/mod.rs:312).

Axum extracts handler arguments before the handler body runs. The preceding VerifiedClientInformation extractor (server/core/src/https/extractors/mod.rs:16-91) always returns Ok (line 89) regardless of credentials; authorization is deferred to the handler body, which is never reached.

The existing semantic depth limit (DEFAULT_LIMIT_FILTER_DEPTH_MAX = 12, server/lib/src/constants/mod.rs:212) is enforced in Filter::from_scim_ro (server/lib/src/filter.rs:786) after the PEG parse has already produced an AST, so it cannot prevent the parser itself from blowing the stack.

The production daemon (server/daemon/src/main.rs:735-744) uses new_multi_thread() with default 2 MiB worker stacks; hyper's max_buf_size (~400 KiB) is not lowered (server/core/src/https/mod.rs:708-727), so a 12 KB URI is accepted.

An identical unbounded grammar exists in libs/scim_proto/src/filter.rs:112-276 (not network-reachable, but should be fixed in the same patch).

PoC

curl -sk "https://idm.example.com/scim/v1/Application?filter=$(python3 -c 'print("("*3000+"a+pr"+")"*3000)')"
# → curl: (52) Empty reply from server
# → server journal: "fatal runtime error: stack overflow, aborting", SIGABRT

Release-build threshold measured at ~2 000 nesting levels / ~4 KB:

$ cargo test --release -p kanidm_proto --test scim_filter_depth -- --nocapture
parens depth=1500 len=3004
  -> survived
parens depth=2000 len=4004

thread 'audit_scim_filter_nested_parens' has overflowed its stack
fatal runtime error: stack overflow, aborting
  (signal: 6, SIGABRT: process abort signal)

End-to-end against an in-process server via kanidmd_testkit (no authentication performed):

Testkit server setup complete - http://localhost:18080/
audit_scim_dos: sending unauthenticated GET, url len = 12056

thread '...' has overflowed its stack
fatal runtime error: stack overflow, aborting
  (signal: 6, SIGABRT: process abort signal)

Impact

Process-wide availability loss; no confidentiality or integrity impact.

  • Unauthenticated, default install, no feature flag required.
  • Process abort, not task panic. Stack overflow triggers libstd's guard-page handler, which calls std::process::abort(). tokio's per-task catch_unwind isolation does not apply to aborts. All in-flight HTTP requests, OAuth2/OIDC sessions, LDAP binds, and the web UI are terminated.
  • Repeatable. One ~12 KB GET per crash; a while true; do curl ...; done loop holds the service down indefinitely across supervisor restarts.
  • The 6 011-byte variant (depth=3000) fits under the nginx default large_client_header_buffers limit of 8 KB, so a typical reverse proxy does not mitigate.

Affected: v1.7.0 through master @ edf50b9da.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Unauthenticated GET request with deeply nested parentheses in SCIM filter parameter triggers stack overflow in PEG parser, causing entire kanidmd process to abort.

Vulnerability

CVE-2026-46689 is an unauthenticated denial-of-service vulnerability in Kanidm's SCIM filter parsing. The recursive-descent PEG parser in proto/src/scim_v1/mod.rs allows unlimited nesting of parentheses in the ?filter= query parameter, with rules like "(" e:parse() ")" that re-enter parse() without a depth counter [1][2]. A crafted filter of a few thousand nested parentheses (≈4–12 KB) causes stack exhaustion past the worker thread's stack guard page.

Exploitation

The vulnerability is reachable via any unauthenticated GET request to nine SCIM endpoints, including /scim/v1/Entry, /scim/v1/Person/{id}, and others [1][2]. The filter parameter is parsed by axum's Query extractor before handler execution, and authorization is deferred, so no authentication is required [1][2]. The existing semantic depth limit (DEFAULT_LIMIT_FILTER_DEPTH_MAX = 12) is only enforced after the parser has already run, thus not preventing the stack overflow [1][2].

Impact

Upon stack overflow, Rust's runtime calls std::process::abort(), immediately terminating the entire kanidmd process [1][2]. This results in a complete denial of service, requiring manual restart or automated recovery mechanism.

Mitigation

As of the advisory publication, no patch is available; administrators are advised to restrict access to SCIM endpoints or apply network-level filtering of oversized query parameters.

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2
  • Kanidm/KanidmGHSA2 versions
    <= 1.9.2+ 1 more
    • (no CPE)range: <= 1.9.2
    • (no CPE)

Patches

0

No patches discovered yet.

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

2

News mentions

0

No linked articles in our index yet.