GHSA-53hj-r94p-8c8f json
Kanidm has non-constant-time comparison of OAuth2 client_secret
published 6mo ago modified 6mo ago
- cvss
- 3.7
- version 3.1, GitHub
- cisa kev
- Not listed
- not in CISA's catalog
- epss
- —
- no score, EPSS covers CVEs only
- public exploits
- 0
- none known
Summary
### 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:
```rust // 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
Patch / fix
- crates.io kanidm 1.9.3
Is GHSA-53hj-r94p-8c8f in your dependencies? Fencer shows which of your repositories are affected as soon as an advisory lands, and opens the fix as a pull request.
Check with FencerCVSS scores
| assigned by | version | score | vector |
|---|---|---|---|
| GitHub | 3.1 | 3.7 | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N |
Affected packages
| ecosystem | package | affected | fixed in |
|---|---|---|---|
| crates.io | kanidm | <1.9.3 |
1.9.3 |
Classification
- Weakness
-
- CWE-208 Observable Timing Discrepancy
References
Sources
- GitHub Advisory GHSA-53hj-r94p-8c8f
Fencer Intel keeps one entry per vulnerability: the CVE id wins, then GHSA, and records that alias each other are merged, except that two CVEs always keep separate entries. The same data is available as JSON.