Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🦀
🦀 crates.io
Not in CISA KEV
LOW severity

GHSA-53hj-r94p-8c8f kanidm

LOW

GHSA-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

Published
May 6, 2026
Updated
May 6, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of May 6, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
🦀kanidm

Real-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

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

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🦀crates.iokanidmall versions1.9.3cargo update -p kanidm --precise 1.9.3

Detection & mitigation playbook

Open-source dependency
  1. Detect

    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.

  2. 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.

  3. 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.

  4. 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

### 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: Obs
O3 Security · Impact-Aware SCA

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.

GHSA-53hj-r94p-8c8f: kanidm (Low 3.7) | O3 Security