Windows CTAP layer truncates discoverable credential enumeration at 20 despite numberOfCredentials=42

12 views
Skip to first unread message

神楽坂玉兔

unread,
10:00 AM (3 hours ago) 10:00 AM
to FIDO Dev (fido-dev)

Hi all,

I've hit what appears to be a hard-coded limit in the Windows CTAP stack when a single RP ID has a large number of discoverable credentials on one security key. The authenticator reports 42, Windows enumerates 20. Sharing the trace in case it's useful, and to check whether anyone has seen this before — I couldn't find a prior report.

Environment

  • Windows 11 25H2 (Build 26200)
  • Microsoft Edge 150
  • YubiKey 5 series, firmware 5.7.4, AAGUID b7d3f68e-88a6-471e-9ecf-2df26d041ede
  • 42 discoverable credentials registered under a single RP ID

Steps to reproduce

  1. Register 42 discoverable credentials for one RP ID on a single security key
  2. Trigger navigator.credentials.get() with an empty allowCredentials (discoverable credential flow, userVerification: "required")
  3. Observe the account picker

Expected: all 42 credentials are listed.

Actual: only the 20 most recently created credentials are listed. The remaining 22 are unreachable through this flow. No error is surfaced.

Evidence (Microsoft-Windows-WebAuthN/Operational ETW trace)

  1. The authenticator reports the full count. The first authenticatorGetAssertion response carries CBOR key 0x05 (numberOfCredentials) = 0x182A = 42.
  2. Windows issues only 19 authenticatorGetNextAssertion (0x08) commands, then stops. The authenticator returns success for every one of them; no error code is emitted and no timeout occurs. 1 + 19 = 20.
  3. The response Windows hands back is a CBOR array of length 20 (header 0x94), and its first element still carries numberOfCredentials = 42 — the count and the payload contradict each other within the same structure.

Per §5.3 of the CTAP spec, the platform is expected to call authenticatorGetNextAssertion numberOfCredentials - 1 times, accumulate the user information into a credentialInfo list, and present that list for user selection. Windows received 42 and issued 19 calls.

Cross-checks ruling out other layers

  • Not the authenticator. python-fido2 driving the same CTAP getAssertion / getNextAssertion sequence against the same key enumerates all 42. ykman fido credentials list also shows 42. Firmware 5.7 supports up to 100 discoverable credentials; remainingDiscoverableCredentials was 56 at capture time.
  • Not the browser. No field in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS, nor in PublicKeyCredentialRequestOptions, allows an RP or client to bound the number of credentials returned, and the trace confirms no such parameter is passed. The enumeration loop and the truncation both occur in the CTAP service process (NT AUTHORITY\NETWORK SERVICE); the webauthn.dll events on the browser side receive an already-truncated array.

Impact

Since CTAP returns credentials newest-first, the dropped 22 are the oldest. From the user's perspective, older accounts silently disappear from the picker with no error and no indication anything is missing. Recovery requires the RP to fall back to a username-first flow so that a non-empty allowCredentials is supplied.

Admittedly 42 credentials under one RP ID is an unusual density, but it is well within what firmware 5.7 supports, and nothing in the spec suggests a platform may cap the enumeration.

Full ETW trace available on request (redacted).

Thanks,

LeterX

Tim Cappalli

unread,
10:47 AM (2 hours ago) 10:47 AM
to 神楽坂玉兔, FIDO Dev (fido-dev)
Hi - It's best to submit this via the Windows Feedback Hub app. 

--
You received this message because you are subscribed to the Google Groups "FIDO Dev (fido-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fido-dev+u...@fidoalliance.org.
To view this discussion visit https://groups.google.com/a/fidoalliance.org/d/msgid/fido-dev/b19d9442-cd7a-46fb-a3fe-3a890d890253n%40fidoalliance.org.
Reply all
Reply to author
Forward
0 new messages