Requests with `uv = required` and `uv = preferred` are sent to CTAP2 devices with unconfigured user verification
@micolous is already working on this.
Since Aug 20, 2026.
Assessment
This issue has not been assessed yet.
Description
Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=2070758
In #372, I added options for changing the user verification requirement in the ctap2.rs example, and made it validate the UV bit of the response. While testing #370, I discovered some other issues with the authenticator selection algorithm.
According to CTAP 2.3 §6.1.1 (Platform actions for MakeCredential) and §6.2.1 (Platform Actions for GetAssertion):
-
if an authenticator is not protected by some form of user verification, and user verification is required, the platform should cancel the action and perform some setup process (ie: #223)
-
if the authenticator is protected by some form of user verification or the RP prefers enforcing user verification (
uv = preferred | required), it should then it should plan to use UV. If UV is unconfigured (ie: RP prefers enforcing user verification), it should perform some setup process.
According to WebAuthn 3 §5.8.6 (User Verification Requirement) (emphasis added):
required: The Relying Party requires user verification for the operation and will fail the overall ceremony if the response does not have the UV flag set. The client MUST return an error if user verification cannot be performed.preferred: The Relying Party prefers user verification for the operation if possible, but will not fail the operation if the response does not have the UV flag set.discouraged: The Relying Party does not want user verification employed during the operation (e.g., in the interest of minimizing disruption to the user interaction flow).
CTAP 2.3 §6.1.1 and §6.2.1 suggests we should take the same interpretation of "preferred" as WebAuthn implementations take for §5.4.6 Resident Key Requirement (if an authenticator supports resident keys, they are used). We can then turn this into a truth table:
| RP's UV requirement | Authenticator supports UV | UV is configured | Expected outcome |
|---|---|---|---|
required |
yes | yes | use UV |
required |
yes | no | rejected |
required |
no (CTAP1) | - | rejected |
preferred |
yes | yes | use UV |
preferred |
yes | no | rejected, because UV is "possible" |
preferred |
no (CTAP1) | - | UV skipped |
discouraged |
yes | yes | UV skipped if possible[^0] |
discouraged |
yes | no | UV skipped if possible[^1] |
discouraged |
no (CTAP1) | - | UV skipped |
[^0]: Skipped when alwaysUv = false | unset (CTAP 2.3 §6.1.2 Step 6) and (makeCredUvNotRqd = true && rk = true) || makeCredUvNotRqd = false | unset (Steps 7 and 8)
[^1]: Skipped when alwaysUv = false | unset (CTAP 2.3 §6.1.2 Step 6. Steps 7 and 8 don't apply)
The actual behaviour with a non-resident credential, using USB authenticators that have a PIN configured, that support PIN but aren't configured, and don't support UV at all (CTAP1):
| RP's UV requirement | Authenticator supports PIN | PIN is set | Firefox 153 [^4] | Chromium 151 | webauthn-authenticator-rs 0.6 [^5] |
Windows 11 25H2 [^6] | Safari 26.6.2 on macOS 26.6.2 |
|---|---|---|---|---|---|---|---|
required |
yes | yes | use PIN | use PIN | use PIN | use PIN | use PIN |
required |
yes | no | PIN skipped ❌ | Prompts to set PIN | rejected [^3] | Prompts to set PIN | Prompts to set PIN |
required |
no (CTAP1) | - | fails (#371) | "can't be used" | not supported | "can't be used" | device ignored |
preferred |
yes | yes | use PIN | use PIN | use PIN | use PIN | use PIN |
preferred |
yes | no | PIN skipped ❌ | PIN skipped ❌ | rejected [^3] | Prompts to set PIN | PIN skipped ❌ |
preferred |
no (CTAP1) | - | PIN skipped | PIN skipped | not supported | PIN skipped | PIN skipped |
The discouraged behaviour is correct for all tested implementations.
Firefox/authenticator_rs incorrect behaviour for required then relies on the RP actually checking the UV bit in the response, and some RPs don't [^2]. While this isn't a security issue in Firefox, it is non-spec-compliant behaviour.
[^2]: Not checking the UV bit is absolutely a security issue for the RP, because otherwise an attacker could steal an authenticator, modify the RP's request to set uv = discouraged, and bypass UV. If the RP checks the bit, then this attack would fail.
[^3]: webauthn-authenticator-rs 0.6 doesn't allow a user to configure PIN/UV during a registration or authentication ceremony (ie: doesn't implement "the platform recovers in some fashion out of scope for these actions" per CTAP 2.3 §6.1.1)
[^4]: Using authenticator-rs as a backend, eg: on Linux
[^5]: Using its native ctap2 backend with the usb transport.
[^6]: Tested via webauthn-authenticator-rs 0.6 with the win10 backend, to minimise browser-level interference.
- Dominant language
- Rust
- Stars
- 316
- Forks
- 82
- Avg merge
- 4d 20h
- Merged PRs (30d)
- 1
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from mozilla/authenticator-rs
-
Difficulty 1/5 Under an hour Newbie friendliness 68/100
mozilla/authenticator-rs#347 ·
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 48/100
mozilla/authenticator-rs#376 ·
-
Difficulty 3/5 1-2 days Newbie friendliness 52/100
mozilla/authenticator-rs#375 · 1 comment ·
-
mozilla/authenticator-rs#371 · 1 assignee ·
-
mozilla/authenticator-rs#367 · 1 assignee ·
All issues in mozilla/authenticator-rs
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
kwakseongjae/auto-hwp#319 ·
-
area:cli bug filter-quality good first issue priority:medium
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
bevyengine/bevy#25861 ·
-
comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ClickHouse/ClickHouse#121222 ·
-
enhancement remote
Difficulty 2/5 1-3 hours Newbie friendliness 68/100