GHSA-22w3-693w-x895: webauthn-rs-core/webauthn-authenticator-rs: Origin validation mismatch possible when subdomains are allowed
Summary`webauthn-rs-core` ([Relying Party][rp]) and `webauthn-authenticator-rs` ([client][]) checked that [an `Origin` in `CollectedClientData`][origin] is valid for [an RP ID][rpid] with [`str::ends_with()`][ends-with], [without checking for a dot (`.`) before the RP ID when allowing subdomains][registerable-suffix].This check is flawed, and could allow requests from an attacker-controlled domain such as `hermit-crab.example` to be accepted for the RP ID `crab.example` (assuming `.example` was publicly-registerable TLD) when the RP allows authenticating from a subdomain (disabled by default in `webauthn-rs-core` and `webauthn-rs`).In `webauthn-rs-core`, this **only** applies when:[`WebauthnCore::allow_subdomains_origin`](https://docs.rs/webauthn-rs-core/0.5.4/webauthn_rs_core/struct.WebauthnCore.html#method.new_unsafe_experts_only) is `true` (the default is `false`), *and*the attacker could register a domain that ends with the RP ID as a raw string, *and*,the client does not implement these checks correctly either`webauthn-rs` can set `allow_subdomains_origin` via [`WebauthnBuilder::allow_subdomains`](https://docs.rs/webauthn-rs/0.5.4/webauthn_rs/struct.WebauthnBuilder.html#method.allow_subdomains). Fixing the bug in `webauthn-rs-core` also fixes it in `webauthn-rs`.In `webauthn-authenticator-rs`, the flawed check is in [`WebauthnAuthenticator::do_registration()`](https://docs.rs/webauthn-authenticator-rs/0.5.4/webauthn_authenticator_rs/struct.WebauthnAuthenticator.html#method.do_registration) and [`do_authentication()`](https://docs.rs/webauthn-authenticator-rs/0.5.4/webauthn_authenticator_rs/struct.WebauthnAuthenticator.html#method.do_registration).A conforming [Relying Party][rp] implementation would reject such requests, but `webauthn-rs-core` did not.An application can still provide an incorrect `origin` parameter to `webauthn-authenticator-rs`, or use lower-level APIs that bypass these checks entirely, and this is by design.These issues are a violation of [WebAuthn Level 3 §13.4.9](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin), [§5.1.3 Step 8](https://www.w3.org/TR/webauthn-3/#CreateCred-DetermineRpId) and [§5.1.4.1 Step 7](https://www.w3.org/TR/webauthn-3/#GetAssn-DetermineRpId).Details`webauthn-rs-core/src/core.rs` line 1213:https://github.com/kanidm/webauthn-rs/blob/197cddf8487a2dbdd5d374e50d80aa1e4682f3ab/webauthn-rs-core/src/core.rs#L1211-L1216`webauthn-authenticator-rs/src/lib.rs` line 274:https://github.com/kanidm/webauthn-rs/blob/197cddf8487a2dbdd5d374e50d80aa1e4682f3ab/webauthn-authenticator-rs/src/lib.rs#L274-L277`webauthn-authenticator-rs/src/lib.rs` line 335:https://github.com/kanidm/webauthn-rs/blob/197cddf8487a2dbdd5d374e50d80aa1e4682f3ab/webauthn-authenticator-rs/src/lib.rs#L335-L338[`str::ends_with()`][ends-with] performs a raw string suffix match _without_ [enforcing a domain label boundary][registerable-suffix]:Origin | RP ID | Expected result | Result with incorrect `ends_with` check
-- | -- | -- | --
`hermit-crab.example` | `crab.example` | rejected | accepted **(bug!)**
`auth.crab.example` | `crab.example` | accepted | accepted (subdomain)
`crab.example` | `crab.example` | accepted | accepted (exact match)
`hermit-crab.example` | `auth.crab.example` | rejected | rejected
`auth.crab.example` | `auth.crab.example` | accepted | accepted (exact match)FixWhen `webauthn-rs-core` v0.5.5 checks if an `Origin` is a valid subdomain of an RP ID, it will check that it ends with the RP ID prefixed with a dot (`.{rp_id}`). `webauthn-rs` v0.5.5 will be fixed by depending on `webauthn-rs-core` v0.5.5.`webauthn-authenticator-rs` v0.5.5 now uses `webauthn-rs-core`'s checks in `WebauthnAuthenticator`.Regression tests for this bug have been added to both libraries.ImpactWith a **both** a non-conforming [client][] implementation and vulnerable version of `webauthn-rs-core` configured to allow subdomains (not the default), this bug would allow an attacker at `hermit-crab.example` to phish a target's credential for the RP ID `crab.example` by directly proxying a legitimate `navigator.credentials.get()` request on the attacker's domain.However, _conforming_ [client implementations][client] (ie: all web browsers) will refuse to process WebAuthn requests for an RP ID that does not match the `Origin` of the current page and is not [a related `Origin`](https://www.w3.org/TR/webauthn-3/#sctn-related-origins).In the scenario above with _conforming_ client-side checks, this would force the attacker to change the request's RP ID to `hermit-crab.example` (the attacker's `Origin`). This would also change the RP ID hash, [and `webauthn-rs-core` would reject it](https://github.com/kanidm/webauthn-rs/blob/197cddf8487a2dbdd5d374e50d80aa1e4682f3ab/webauthn-rs-core/src/core.rs#L825-L840) (per [WebAuthn §7.2 Step 15](https://www.w3.org/TR/webauthn-3/#rp-op-verifying-assertion-step-rpid-hash)).SeverityPer [WebAuthn §13.4.9](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin):The [Relying Party](https://www.w3.org/TR/webauthn-3/#relying-party) MUST NOT accept unexpected values of [origin](https://www.w3.org/TR/webauthn-3/#dom-collectedclientdata-origin), as doing so could allow a malicious website to obtain valid [credentials](https://www.w3.org/TR/credential-management-1/#concept-credential). Although the [scope](https://www.w3.org/TR/webauthn-3/#scope) of WebAuthn credentials prevents their use on domains outside the [RP ID](https://www.w3.org/TR/webauthn-3/#rp-id) they were registered for, the [Relying Party](https://www.w3.org/TR/webauthn-3/#relying-party)’s origin validation serves as an additional layer of protection in case a faulty [authenticator](https://www.w3.org/TR/webauthn-3/#authenticator) fails to enforce credential [scope](https://www.w3.org/TR/webauthn-3/#scope).Unfortunately, [the chain needed to exploit this bug makes it difficult to classify with the CVSS framework](https://www.first.org/cvss/v4.0/user-guide#Vulnerability-Chaining). Kanidm came up with anywhere between "low" and "high" depending on the approach, and GitHub only provides one CVSS field for everything.An attacker could easily bypass a _correctly-implemented_ server-side `Origin` check, if they can convince a target to use their authenticator with [an attacker-controlled client device](https://fidoalliance.org/specs/common-specs/fido-security-ref-v2.1-ps-20220523.html#dfn-t-1.3.2) or [buggy/malicious client application](https://fidoalliance.org/specs/common-specs/fido-security-ref-v2.1-ps-20220523.html#dfn-t-1.3.1). FIDO's Security Reference [assumes that "the FIDO user device and applications involved in a FIDO operation are trustworthy agents of the user"](https://fidoalliance.org/specs/common-specs/fido-security-ref-v2.1-ps-20220523.html#dfn-sa-4), and violating that [limits the protections FIDO can provide](https://fidoalliance.org/specs/common-specs/fido-security-ref-v2.1-ps-20220523.html#discussion), so it would be ridiculous to describe those bypasses as a "high" severity vulnerability.However, `webauthn-rs-core` should take reasonable steps to prevent these sorts of issues where it can, especially when they're part of the WebAuthn specification.Due to the complex preconditions and non-default configuration required to execute a successful attack, and that it is *not exploitable* in popular web browsers, Kanidm considers this a **low severity** issue.
CVSS v4.0: 2.3