GHSA-53hj-r94p-8c8f — kanidm
LOWGHSA-53hj-r94p-8c8f is a low-severity (CVSS 3.7) vulnerability in kanidm. A fix is available for kanidm — see the affected versions and patch details below.
Kanidm has non-constant-time comparison of OAuth2 client_secret
Real-World Exposure
kanidmReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.
Description
Summary
The kanidmd OAuth2 token-exchange (/oauth2/token) and token-introspection (/oauth2/token/introspect) endpoints compare the supplied client_secret against the stored secret using Rust's PartialEq on String, which short-circuits on the first mismatching byte. This produces an observable timing discrepancy that varies with the length of the matching prefix.
Details
- https://github.com/kanidm/kanidm/blob/master/server/lib/src/idm/oauth2.rs#L1135 — variable-time comparison in
check_oauth2_token_exchange - https://cwe.mitre.org/data/definitions/208.html — CWE-208: Observable Timing Discrepancy
PoC
Static analysis only — no timing-recovery script was run because remote recovery of a 48-byte high-entropy secret over HTTPS is not practically demonstrable. The variable-time behaviour is established by inspection:
// server/lib/src/idm/oauth2.rs:1135 (check_oauth2_token_exchange)
if authz_secret == &secret { … } else { return Err(Oauth2Error::AuthenticationRequired); }
String: PartialEq delegates to <[u8] as PartialEq>::eq, which checks length equality then iterates byte-by-byte and returns on the first difference.
Impact
An unauthenticated network attacker who can reach the OAuth2 endpoints can submit arbitrary client_id/client_secret pairs and observe response latency. In principle the early-exit comparison leaks the position of the first mismatching byte, providing a timing oracle toward incremental recovery of a confidential client's secret. In practice the stored secret is a server-generated 48-character high-entropy string, the comparison runs inside an async tokio handler behind TLS, and network jitter is orders of magnitude larger than a single byte-compare — so remote recovery is not considered realistic with current techniques. This is a hardening issue rather than a practically exploitable vulnerability.
Affected versions
All published kanidmd_lib releases; the comparison is still variable-time on master at 1.10.0-dev
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🦀crates.io | kanidm | all versions | 1.9.3cargo update -p kanidm --precise 1.9.3 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for kanidm, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update kanidm to 1.9.3 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-53hj-r94p-8c8f is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-53hj-r94p-8c8f can be triaged on real exposure rather than presence alone.
Tailored to GHSA-53hj-r94p-8c8f. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-53hj-r94p-8c8f in your dependencies?
O3 Security finds GHSA-53hj-r94p-8c8f across crates.io dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.