fix(webauthn): largeBlob.read no longer leaks largeBlobKey to RP#198
Merged
AlfioEmanueleFresta merged 2 commits intoMay 12, 2026
Merged
Conversation
4f484fb to
63fd2d2
Compare
msirringhaus
approved these changes
May 11, 2026
Collaborator
msirringhaus
left a comment
There was a problem hiding this comment.
Yep, that's right. I was actually planning on finalizing my LargeBlob-PR, that would have fixed that, too, but that got delayed by other stuff. This is a good workaround until then
AlfioEmanueleFresta
added a commit
that referenced
this pull request
May 12, 2026
Per review on #198: keep the per-credential largeBlobKey only on the CTAP-level Ctap2GetAssertionResponse. Surfacing it on the public Assertion struct gives callers a foot-gun to forward straight to the RP, which is exactly the disclosure this PR is meant to prevent. The follow-up authenticatorLargeBlobs PR (#206) can read the key directly off the CTAP response.
63fd2d2 to
34571aa
Compare
When the RP requests `largeBlob: { read: true }`, libwebauthn was populating
the WebAuthn response's `blob` field with the per-credential `largeBlobKey`
(a 32-byte AES-256-GCM key) instead of the decrypted blob payload. The CTAP
2.1 `authenticatorLargeBlobs` command is not yet implemented; until it is,
the safe behaviour is to drop the key from the WebAuthn response.
The CTAP-level `Ctap2GetAssertionResponse.large_blob_key` field is unchanged
so the next PR can wire up the proper flow.
Refs: WebAuthn L3 sec. 10.1.5, CTAP 2.1 sec. 6.10.
Per review on #198: keep the per-credential largeBlobKey only on the CTAP-level Ctap2GetAssertionResponse. Surfacing it on the public Assertion struct gives callers a foot-gun to forward straight to the RP, which is exactly the disclosure this PR is meant to prevent. The follow-up authenticatorLargeBlobs PR (#206) can read the key directly off the CTAP response.
34571aa to
5388273
Compare
AlfioEmanueleFresta
added a commit
that referenced
this pull request
May 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Per WebAuthn L3 sec. 10.1.5 (largeBlob extension), the relying party expects the
bloboutput to be the decrypted plaintext blob payload, fetched by the platform via the CTAPauthenticatorLargeBlobscommand using the per-credentiallargeBlobKeyas an AES-256-GCM key. The library was instead writing the rawlargeBlobKeyintobloband never callingauthenticatorLargeBlobs. That means an RP receives the AES key itself (not the blob), and if the RP can also read the device'slargeBlobArray(publicly readable region of the authenticator over CTAP), it can decrypt and forge entries.Until
authenticatorLargeBlobsis wired up (follow-up PR #206), the safe behaviour is to setlarge_blob.blob = None. The CTAP-level model keeps the field so the follow-up can use it.Changes
largeBlobKeyinto the WebAuthnlarge_blob.bloboutput.Ctap2GetAssertionResponse.large_blob_keyremains so the next PR can use it.References
largeBlob)authenticatorLargeBlobs(0x0C)