Every CVE Search/ Get API key

CVE-2026-46689

Kanidm: Unauthenticated process abort via SCIM filter stack exhaustion

8.7 HighFix available

Kanidm is an identity management platform. Prior to version 1.9.3, 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. This issue has been patched in version 1.9.3.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
High

Exploit likelihood

0.32%Up 0.3 points since Jun 11, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.7

Kanidm: Unauthenticated process abort via SCIM filter stack exhaustion

Kanidm is an identity management platform. Prior to version 1.9.3, 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. This issue has been patched in version 1.9.3.

Record
CVE-2026-46689
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-248, CWE-400, CWE-674
Updated
2026-11-02
EUVDEUVD-2026-36133 8.7

Kanidm is an identity management platform. Prior to version 1.9.3, 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. This issue has been patched in version 1.9.3.

Record
EUVD-2026-36133
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-r5fr-9gmv-jggh 8.7

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

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<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-task catch_unwind isolation does not apply to aborts. All…
Record
GHSA-r5fr-9gmv-jggh
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-248, CWE-400, CWE-674
Updated
2026-11-02
NVD 8.7

Kanidm is an identity management platform. Prior to version 1.9.3, 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. This issue has been patched in version 1.9.3.

Record
CVE-2026-46689
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Weakness
CWE-248, CWE-400, CWE-674
Updated
2026-11-02
OSV 8.7

Kanidm: Unauthenticated process abort via SCIM filter stack exhaustion

Kanidm is an identity management platform. Prior to version 1.9.3, 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. This issue has been patched in version 1.9.3.

Record
CVE-2026-46689
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-248, CWE-400, CWE-674
Updated
2026-11-02
OSVGHSA-r5fr-9gmv-jggh 8.7

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

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<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-task catch_unwind isolation does not apply to aborts. All…
Record
GHSA-r5fr-9gmv-jggh
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-248, CWE-400, CWE-674
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
scim_proto
crates.io
through 1.9.2
1.9.3
kanidm_proto
crates.io
through 1.9.2
1.9.3
scim_proto
crates.io
before 1.9.3
1.9.3
kanidm_proto
crates.io
before 1.9.3
1.9.3

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-46689 is a high vulnerability (CVSS 8.7) in Kanidm, published May 6, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 24th percentile. Fixed in scim_proto 1.9.3.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open