Repository navigation
Security and Privacy Self Review
Moved from a comment on issue 232 on 2026-10-15. GitHub keeps the earlier versions in that comment's edit history.
This review describes the specification as it stands on main at commit b31343b (2026-09-04). Nothing here assumes an unmerged pull request. Merged and therefore included: #535 (opaque origins rejected), #538 (cross-device security and proximity), #540 (CTAP recommended for cross-device), #557 (InvalidStateError when the document is not fully active), #454 (a user agent MUST support every listed presentation protocol), #515 (validation failures classified into specific exception types), #569 (signing presentation requests), #533 (expanded threat model and malicious payloads), #559 (DigitalCredential declared origin bound), #536 (data clearing and credential availability) and #561 (credential manager chooser and issuance differences). Not included, and so not described below: #534 was closed without merging and #562 (private browsing mode) is still open, as are #520 (protocol validation and enforced response encryption), #528 and #539.
2.1. What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary?
Primarily a credential response: claims an issuer makes about the user, returned to the requesting site. The credential types in scope include a driving license, a passport or other government-issued identity card, a travel authorization document, proof of employment, and proof of education or professional training. This exposure is the purpose of the API. It happens only after the user agent has shown a digital credential chooser and the user has selected a credential. The specification is deliberate that this permission "is not consent", which has legal definitions that may require the credential manager or the verifier to collect it separately.
Two other exposures are worth naming. DigitalCredential.userAgentAllowsProtocol() tells any secure-context page which protocols the user agent allows, without a user gesture (see the userAgentAllowsProtocol() method). And the platform side sees more than the site does: the user agent passes the request data and the top-level origin to the chooser and on to a credential manager, which the specification notes "reveals parts of the user's browsing activity as well as their intent to identify to specific websites and/or credential managers".
2.2. Do features in your specification expose the minimum amount of information necessary to enable their intended uses?
Not by itself, and the specification does not claim otherwise. The API is "agnostic to the credential format and the information contained in it, as well as the protocol used to exchange it", and "What constitutes a validation failure is protocol-specific", so how much a verifier asks for is decided by the protocol and the credential format, not here. Selective disclosure appears as an expectation of protocols in the informative Privacy Considerations ("Protocols are expected to facilitate selective disclosure by allowing the verifier to specify the exact claims needed"), not as a requirement on verifiers or user agents. The specification instead assumes verifiers may over-ask: it states that "from a user agent's perspective, verifiers are potential attackers" with "incentives that motivate unnecessary requests and abuse". Since #454, a user agent must support every listed presentation protocol, so it can no longer minimize by declining to support a protocol.
2.3. How do the features in your specification deal with personal information, personally-identifiable information (PII), or information derived from them?
Through gating rather than inspection. The interfaces are exposed only in secure contexts; a request from an opaque origin, such as a data: document or a document sandboxed without allow-same-origin, is rejected with a SecurityError (the specification declares DigitalCredential origin bound, and Credential Management does the rejecting); and a call requires transient activation, which the algorithm consumes, so a site cannot request or issue silently. User mediation is implicitly required and cannot be overridden by the caller. The promise resolves with a credential only if the user selected one in the chooser; a cancellation or no selection rejects with a NotAllowedError and no credential data reaches the origin. As in 2.1, the specification calls this permission and not consent.
There is no separate path for it: a sensitive credential travels the same secure context, transient activation and mediation path as any other (see 2.3). Everything the specification says specifically about sensitivity is non-normative. It lists what a user needs in order to decide, including the origin of the requesting verifier, what is being requested or would be revealed, whether responding enables tracking, and which credential managers are involved, but the chooser is a platform-provided interface that is largely out of scope, and the specification defines no prompt text of its own. Only the accessibility of that interface carries normative requirements; the privacy expectations for it are advice, and issue #252 asks whether they should become requirements.
2.5. Does data exposed by your specification carry related but distinct information that may not be obvious to users?
Yes. The specification's "Leaking incidental data with credential presentations" section says a presentation "generally includes more information than the content the verifier is requesting access to", usually "at least a signature of the issuer and the credential manager, and potentially other metadata", and that this can be used to reidentify and fingerprint users. Responses are assumed to be encrypted to the verifier, so the user agent cannot strip or filter any of it. The mitigation is non-normative guidance to user agents, which "can help protect users against this type of tracking through clearly highlighting which information likely gets shared with the verifier beyond what was requested", not a requirement on protocols.
2.6. Do the features in your specification introduce new state for an origin that persists across browsing sessions?
No state of its own. Nothing in the algorithms writes to storage, the credential request coordinator's state lasts only for one request and belongs to a single top-level traversable, and [[Store]] defers to the Credential Management default, which throws a NotSupportedError, so a digital credential cannot be put in the credential store. What can persist is the response: the specification notes credentials can contain "permanent, irrevocable, unique identifiers", which a verifier can store and use to re-identify the user later. The specification treats that as a privacy risk for user agents to mitigate rather than as a feature. Its Data Clearing and Persistent State section says the API "does not introduce new browser-managed persistent state or local storage mechanisms", and that clearing a user's browsing data "generally does not clear or affect the credentials held within those external managers".
2.7. Do the features in your specification expose information about the underlying platform to origins?
Yes, in one deliberately narrow way. DigitalCredential.userAgentAllowsProtocol() reports which presentation and issuance protocols the user agent allows. It is static, available in any secure context, and needs no user activation, because its purpose is to let a site choose a protocol or fall back before calling the API. The specification bounds the leak: user agents "MUST NOT vary the response value based on any information about availability of hardware, presence or configuration of software, credential managers, or digital credentials, or user configuration or preferences", the value "SHOULD vary only by user agent major version", and the result is therefore "at best, equivalent to a user agent version". Since #454 requires support for every listed presentation protocol, conforming user agents should answer the same way for those.
Beyond that, the API "does not enable sites to learn whether a credential is available without first going through a user permission flow". The specification also makes refusals deliberately ambiguous: NotAllowedError "is deliberately indistinguishable from the error returned when the user cancels the operation, so that a website cannot determine whether a request was refused by the user or by the user agent, nor infer anything about the user's configuration or credentials". A user agent that cannot support presentation requests at all is observably different, since the call falls back to the Credential Management default behavior.
Yes. The user agent hands the platform a request context holding the validated requests and the top-level origin. Each request is a protocol identifier from a closed enumeration plus a required data object that the site supplies, which the user agent serializes to JSON and validates per protocol; the specification does not otherwise constrain its contents, so effectively arbitrary protocol-specific data passes through. Two clarifications: there is no relying-party identifier and no requested-credential-types member in this API, so anything of that kind travels inside data; and the origin the platform receives is the top-level origin, computed by the user agent rather than supplied by the caller, so an embedded cross-origin frame cannot assert an origin of its own. Requests are deliberately unencrypted, "enabling user-agent inspection for risk analysis".
No. While the underlying credential manager may use platform biometric authentication to authorize the release of a credential, this is handled entirely by the platform and is not exposed to the web origin.
No. The credential response comes back as a string that the user agent parses with the JSON parser and rejects unless the result is an object, so what reaches the page is data.
Yes, indirectly: the credential the user selects may live on a second device, such as a phone acting as the credential manager. The origin plays no part in reaching it. A site passes only protocol identifiers and protocol-specific request data, and the specification gives it no way to discover, name, address or pair with another device; platform frameworks, native APIs and the hardware holding credentials are out of scope. Nothing about the second device comes back either, since userAgentAllowsProtocol() must not vary with hardware availability or installed credential managers. For these flows the specification recommends CTAP so that proximity and cryptographic security are established by the protocol rather than by the API.
2.12. Do features in this specification allow an origin some measure of control over a user agent's native UI?
Only to invoke it and to dismiss it. Calling get() triggers the platform's digital credential chooser and calling create() triggers a credential manager chooser. The requests passed in are the input to the chooser, but the site cannot style or lay out the chooser and cannot put its own text in it. The specification still carries an editorial note, linked to #44 (closed on GitHub on 2026-06-08), that asks whether the API should let sites give in-context explanations. Today they cannot. Dismissal is under site control: aborting a passed AbortSignal dismisses the chooser and rejects with the signal's abort reason, which the accessibility considerations address by saying sites SHOULD allow sufficient time. The user agent computes the top-level origin itself, so a site cannot supply a different one. The specification says a user agent may display that origin.
None. This specification defines no nonce, challenge, session identifier or transaction identifier, and the two places where it constructs a DigitalCredential set only protocol and data. Any such value belongs to the presentation or issuance protocol carried inside those payloads. Visibility differs by direction on purpose: requests are transmitted unencrypted so the user agent can inspect them for risk analysis, while responses are assumed encrypted and treated as opaque.
2.14. How does this specification distinguish between behavior in first-party and third-party contexts?
Third-party contexts are blocked by default and need explicit delegation. Two policy-controlled features are defined, digital-credentials-get for presentation and digital-credentials-create for issuance, each with a default allowlist of 'self', so a cross-origin iframe cannot make either kind of request unless the embedder delegates it, for example with allow="digital-credentials-get". The two are deliberately separate, so presentation can be delegated without issuance. One further difference: the request handed to the platform carries the top-level origin, not the embedded frame's origin.
2.15. How do the features in this specification work in the context of a browser's Private Browsing or Incognito mode?
The specification does not say. There is no Private Browsing or Incognito section in the current draft and no text about private, ephemeral or incognito modes, so the behavior is unspecified rather than deliberately delegated. #534, which would have addressed this, was closed without merging; #562 is open. What the text does support is narrow: the API defines no storage of its own, its only state belongs to a per-top-level-traversable coordinator and lasts for one request, [[Store]] throws a NotSupportedError, and how credentials are stored or managed is out of scope. Anything the credential manager or the verifier retains is outside this specification's control.
2.16. Does this specification have both "Security Considerations" and "Privacy Considerations" sections?
Yes, both exist and both are currently marked non-normative. Security Considerations covers the threat model, the in-scope threats (request tampering, API flooding, unauthorized cross-origin access and malicious payloads to the underlying platform), the out-of-scope threats (OS or device compromise, malicious credential managers, protocol and format vulnerabilities), the mitigations, including signing presentation requests, and cross-device security and proximity. Privacy Considerations is longer and covers design alternatives, the spectrum of privacy, protocol and credential-format considerations including unlinkability, unnecessary requests, fingerprinting and data leakage, and user permission and transparency. Privacy Considerations still has open work: it carries thirteen issue boxes, one flagging the whole section as work in progress and another asking whether its user-permission expectations should be normative. Security Considerations has no open issue boxes. The requirements the mitigations rely on are normative in the body of the specification.
No. The API is only available in Secure Contexts.
2.18. What happens when a document that uses your feature is kept alive in BFCache (instead of getting destroyed) after navigation, and potentially gets reused on future navigations back to the document?
[[DiscoverFromExternalSource]] and [[Create]] both delegate to "prepare credential requests", which holds the document and activation checks. A call from a document that is not fully active, which includes a document in BFCache, rejects with an InvalidStateError DOMException. A call from a document that is fully active but not a fully active descendant of a top-level traversable with user attention rejects with NotAllowedError, as does a call without transient activation. Activation is consumed only after those checks pass, so a call that fails one of them does not spend the user's gesture. A call rejected later, because another request is already in progress or because validation fails, spends the gesture. If a document stops being fully active while a request is pending, that request is aborted with an AbortError DOMException. BFCache is not named in the specification; the behavior follows from the fully active checks, so a restored document needs a fresh gesture and a new call.
The pending request is aborted with an AbortError DOMException. There is at most one to abort, since each top-level traversable has exactly one credential request coordinator holding a single active promise. The coordinator leaves its "requesting" state and the chooser is dismissed, so the user cannot keep interacting with a request whose document is gone. The rejection, like the step that would deliver a credential, is queued on the disconnected document's own global, so it runs only if that document becomes fully active again. A response arriving after disconnection therefore cannot reach the document.
Yes, though it defines no new error types. It reuses existing DOMException names and TypeError, says which applies where, and passes through the SyntaxError that JSON parsing throws:
-
SecurityError: the calling document's origin is opaque, for example adata:document or a document sandboxed withoutallow-same-origin(Credential Management rejects these, since the specification declaresDigitalCredentialorigin bound); also when a request is "not permitted for security reasons unrelated to the user, such as the context or transport" -
InvalidStateError: the document is not fully active at call time, or the platform reports that a credential request is already in progress -
NotAllowedError: the document is not a fully active descendant of a top-level traversable with user attention, there is no transient activation, the coordinator is already handling a request, the user cancels or selects nothing, the user agent does not permit the request "based on local policy, configuration, or the user's choices", or the platform does not permit the operation -
TypeError: no request uses a protocol the user agent allows, the request list is empty, the request data is malformed or invalid, or the response parses to something that is not an object -
OperationError: any other validation or platform-level failure -
SyntaxError: the credential manager's response is not valid JSON -
AbortError: the document stops being fully active while a request is pending. A passedAbortSignalthat aborts rejects with the signal's abort reason instead, which is anAbortErrorunless the caller supplied another reason
Two deliberate choices are worth a reviewer's attention. Requests whose protocols are all unsupported are filtered out before transient activation is consumed, so such a call rejects with a TypeError without spending the user's gesture. And NotAllowedError is reused on purpose: it "is deliberately indistinguishable from the error returned when the user cancels the operation, so that a website cannot determine whether a request was refused by the user or by the user agent, nor infer anything about the user's configuration or credentials".
No. The specification defines nothing that varies with input modality or with the presence of assistive technology. The chooser is a platform-provided interface, and what the site receives is a protocol identifier, opaque response data, or one of the exceptions above. The one capability-probing surface, userAgentAllowsProtocol(), must not vary with "user configuration or preferences".
How does a specification like this keep verifiers from asking for more than they need, and what does it say about a user who is being pressured into sharing?
The specification handles over-asking directly and coercion only in part. Its "Unnecessary Requests for Credentials" section names over-asking as "a key privacy risk to the entire digital credentials ecosystem", including "Requests for an excessive amount of information for valid purposes against the principle of data minimization", and it keeps requests readable by the user agent rather than encrypted end to end, so a user agent can inspect a request and act on it. Most of the mitigations are addressed to user agents non-normatively, and the parts that would matter most for a pressured user, what the chooser says and how hard it is to decline, sit with the platform and are largely out of scope. A reviewer should read those expectations as guidance rather than as conformance requirements.
meeting notes