Summary
scimproto and kanidmproto have an authenticated process abort via SCIM filter stack exhaustion
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<ScimEntryGetQuery> 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<DisplayFromStr>")], 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<ScimEntryGetQuery> 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-taskcatch_unwindisolation 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 ...; doneloop holds the service down indefinitely across supervisor restarts. - The 6 011-byte variant (
depth=3000) fits under the nginx defaultlarge_client_header_bufferslimit of 8 KB, so a typical reverse proxy does not mitigate.
Affected: v1.7.0 through master @ edf50b9da.
Crafted input forces the application to consume excessive CPU, memory, or other resources, degrading or denying service. Typical impact: denial of service.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
scim_proto to 1.9.3 or later; kanidm_proto to 1.9.3 or later
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-46689? CVE-2026-46689 is a high-severity uncontrolled resource consumption vulnerability in scim_proto (rust), affecting versions <= 1.9.2. It is fixed in 1.9.3. Crafted input forces the application to consume excessive CPU, memory, or other resources, degrading or denying service.
- Which packages are affected by CVE-2026-46689?
scim_proto(rust) (versions <= 1.9.2)kanidm_proto(rust) (versions <= 1.9.2)
- Is there a fix for CVE-2026-46689? Yes. CVE-2026-46689 is fixed in 1.9.3. Upgrade to this version or later.
- Is CVE-2026-46689 exploitable, and should I be worried? Whether CVE-2026-46689 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-46689 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-46689?
- Upgrade
scim_prototo 1.9.3 or later - Upgrade
kanidm_prototo 1.9.3 or later
- Upgrade