v1.1 - Interactive Authorization Endpoint (Presentation-During-Issuance): Cross-Session Holder-Binding Confusion
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 125
- Forks
- 41
- PR merge metrics
- No merged PRs in 30d
Description
Interactive Authorization Endpoint (Presentation-During-Issuance): Cross-Session Holder-Binding Confusion — Tamarin-Verified Attack and Fix
In the Interactive Authorization Endpoint (IAE) "presentation-during-issuance" flow, the Credential Issuer acts as an OpenID4VP Verifier: to obtain a derived credential the Wallet must first present an existing one. The new credential's subject claims are taken from the presented credential, while its holder-binding key is taken from the issuance key proof — and §6 mandates no cryptographic link between the two. We show that, under the spec as written (v1.1 editor's draft), this lets an adversary obtain a credential carrying an honest victim's subject claims but bound to a holder key the adversary controls, i.e. a usable impersonation credential. Crucially, the attack requires no compromise of any long-term key — not the Issuer's, not the Authorization Server's and not the victim's holder key — which distinguishes it from token-leak attack classes.
We have formally verified the attack in Tamarin against the protocol as written, evaluated a natural fix that fails for a non-obvious reason that formal analysis surfaces, and verified two configurations that close it: a holder-key-continuity check, and a more flexible presenter-signed commitment that closes the attack while preserving per-credential key unlinkability. The fixes anchor the missing binding at material the Issuer already trusts (the accepted presentation's holder key), not at the Wallet's freely re-mintable inputs.
This corresponds to the "generalized holder-binding / subject gap" instantiated in the new IAE machinery: §6 mandates no linkage between the key/subject of the presented credential and the key/subject of the credential being issued, so the protocol permits a trace in which the entity that completes the presentation step is not the entity whose key is bound into the new credential.
Affected Spec
OpenID for Verifiable Credential Issuance 1.1 (editor's draft, openid-4-verifiable-credential-issuance-1_1-01). The Interactive Authorization Endpoint is new in v1.1; the synchronous and pre-authorized-code flows in 1.0 are not affected by this issue. Section numbers are per the editor's draft and may shift before v1.1 Final.
- §6 (Interactive Authorization Endpoint) — the flow under which the attack manifests. For the
urn:openid:dcp:iae:openid4vp_presentationinteraction type, the OpenID4VP request is embedded in the Issuer'srequire_interactionresponse and the VP is returned to the same endpoint viaresponse_mode = iae_post/iae_post.jwt. §6 says nothing requiring the holder/subject of the presented VP to equal the holder/subject of the credential being issued, and mandates no proof of same-end-user control across the two steps; what the Issuer (acting "as a Verifier") does with the presented claims is treated as out of scope. - §6.2.1.4 (Preventing Session Fixation Attacks) — requires the AS to associate the OpenID4VP
noncewith theauth_sessionand to verify the presentation uses the samenonce. This is a per-flow server-state association (nonce ↔ session), not a term-level cryptographic binding of holder keys. It does not close this gap (and the model confirms it). - §6.2.1.1 — explicitly allows the presented VP's Credential Format to differ from the format used for issuance, reinforcing that the two stages are only loosely coupled.
- Appendix A.2.5 / A.3.5 (Holder-Binding audience) — the VP's holder-binding audience must be
iar:<IAE-URL>, binding the presentation to the Issuer endpoint URL and nothing else (in particular, not to any issuance key). - §9 / key proof (
openid4vci-proof+jwt) — the issuance key proof is bound to the Credential Issuer Identifier and to nonce-endpoint freshness, but not to the authenticated/presented subject. Whoever completes the issuance exchange chooses the binding key. - §13.4 (Split-Architecture Wallets) — already acknowledges the principal real-world adversary (a malicious/compromised provider-operated Wallet backend) but provides no mitigation for this cross-stage binding gap.
The corresponding holder-binding requirements I-40 and P-50 of the companion document Security and Trust in the OpenID4VC Ecosystem (§4.3) exist as requirements but are not protocol-enforced for this path.
Threat Model
The adversary is a Dolev–Yao adversary (Web Attacker + Network Attacker per §6.1 of the companion document). The distinguishing feature of this issue is what the adversary does not need:
- It does not compromise the Credential Issuer's signing key.
- It does not compromise the Authorization Server's signing key.
- It does not compromise the victim's holder private key, response-encryption key, or any other long-term secret.
- It does not rely on any leaked access token, DPoP key, or transaction ID.
The only adversary capabilities required are:
- The adversary runs its own issuance session with the same Credential Issuer
CI(it is, or can act as, a Wallet talking toCI), generating its own holder keypair(skH_Adv, pkH_Adv). - The adversary can cause an honest holder's genuine presentation to be produced against
CI's (Issuer-signed) presentation request for the adversary's session — i.e. it interposes on presentation-request delivery / VP return for the sameCI.
Capability (2) has two faithful instantiations, both already recognized by the spec/companion document:
- Malicious or compromised split-architecture Wallet backend (§13.4). The provider-operated backend mediates the user's interaction with
CI. When the user authorizes a presentation-during-issuance, the backend feeds the device the attacker session'snonce, the device (holdingskHin its secure element) signs a genuine KB-JWT, and the backend redeems the resulting Access Token in the attacker session and requests the credential bound to a backend-held key. No key is ever leaked; the backend abuses its architectural position. (The audience binding makes this same-Issuer: the VP is bound toiar:CI, so a different issuer cannot harvest it — the attack is specifically a cross-session confusion at one Issuer, not cross-issuer relay.) - Dolev–Yao interposition / concurrent sessions. Any positioning from which the adversary can deliver
CI's own (signed) presentation request to the honest holder and relay the holder's VP back toCIin the adversary's session.
In both cases the honest holder performs a presentation it intended to perform; the protocol simply fails to tie the credential subsequently issued to that holder's key. We do not assert how common split-architecture deployments are — only that §13.4 establishes the trust boundary as recognized, which is sufficient.
Composability note. §6.1 of the companion document protects a non-compromised Wallet against compromised Issuers and Verifiers, but does not extend that protection to a compromised peer Wallet / backend on the same footing. This issue is an instance worth correcting under that principle.
Attack: Cross-Session Holder-Binding Confusion (A1)
On the "A1" label. "A1" is the identifier this attack vector carries in our internal threat catalogue. We retain it in this issue only because it is the prefix used throughout the accompanying Tamarin artifacts — the theory is
OID4VCI_A1and the lemmas are nameda1_no_impersonation,a1_attack_witness,a1_holder_continuity_*, etc. — so the prose here maps one-to-one onto the proof files. It denotes the cross-session holder-binding confusion described below; it is not a severity rating and not a reference to any external (e.g. OWASP/CWE) catalogue.
The adversary opens its own auth_session with CI, relays CI's Issuer-signed presentation request to an honest victim, consumes the victim's genuine VP in the adversary's session, and then completes issuance with a key proof under the adversary's own key. CI, finding no requirement that the issuance key match the presented holder key, issues a credential carrying the victim's subject claims bound to the adversary's key.
Attack steps
- The honest victim
Wid_Vholds a prerequisite credential issued by an honest Prerequisite IssuerPI, bound to the victim's holder keypkH_pres = pk(skH_pres)(held in the device-side trust domain; never leaked). - The adversary generates its own holder keypair
(skH_Adv, pkH_Adv)and starts an IAE session withCI: it sendsiae-initand receivesCI'srequire_interactionresponse containing an Issuer-signed presentation requestpresReq(nonce_A, aud = iar:CI)for the adversary'sauth_session_A. - The adversary causes
presReq(nonce_A, aud = iar:CI)to be presented to by the victim (via the §13.4 backend position, or DY interposition). The victim returns a genuine VP: the prerequisite VC plus a KB-JWT signed underskH_presover(iar:CI, nonce_A). - The adversary submits
(auth_session_A, VP)toCI's IAE endpoint.CIverifies the VP: the prerequisite VC verifies underPI's key; the KB-JWT verifies underpkH_pres;nonce_Amatchesauth_session_A's nonce, so §6.2.1.4 is satisfied.CImints an Access Token bound toauth_session_A, storing the victim'spkH_presand subject claims. - The adversary sends a Credential Request carrying the Access Token, a key proof signed under
skH_Adv, and holder keypkH_Adv, plus an attacker-chosen response-encryption key. CIaccepts: the key proof is self-consistent (it verifies underpkH_Adv), and nothing requirespkH_Adv = pkH_pres.CIissues a credential carrying the victim's subject claims bound topkH_Adv, encrypted to the attacker's key.- The adversary decrypts and obtains a credential about the victim's subject, cryptographically bound to a key the adversary controls — and therefore presentable by the adversary as if they were the victim.
What the attacker gains. A credential asserting the victim's identity/attributes, bound to an attacker-held key — a violation of holder-binding requirements I-40 / P-50 and a full impersonation primitive. (A confidentiality-only variant, in which the credential is instead bound to the victim's key but encrypted to the attacker, is also reachable; the holder-key substitution above is the stronger outcome and the one we headline.)
Why the spec does not currently prevent this
The presentation is bound to three things — the opaque auth_session handle, the iar:CI audience, and the OpenID4VP nonce — but none of these relates the presented holder key k_pres to the issuance key-proof key k_proof:
- §6.2.1.4 binds
nonce ↔ auth_session. In the attack,nonce_Agenuinely belongs toauth_session_A, so the check passes. Session-fixation prevention does not imply holder-key continuity. - Appendix A.2.5 / A.3.5 binds the VP to
iar:CI(the Issuer endpoint), not to any issuance key. - The key proof (§9) proves possession of some holder key and binds the Issuer identifier and a fresh nonce, but the Issuer never checks that this key is the presenter's key.
So at the term level k_pres and k_proof are independent objects with no relating equation. Standard channel/signature abstractions do not rule the attack out: modelling TLS as a confidential channel does nothing (there is no interception), and signatures are unforgeable (no signature is forged — the victim's KB-JWT is genuine and the adversary signs its own key proof with its own key). It is a binding failure, not an interception or a forgery.
Tamarin Formal Verification
We formalized the IAE presentation-during-issuance flow in Tamarin (1.12.0 / Maude 3.5.1) from a single source with four #ifdef configurations. The model uses standard Dolev–Yao primitives (signing, public-key encryption, hashing); folds the OAuth/PAR + Token Endpoint into one opaque, session-bound Access Token gating the Credential Endpoint; and includes explicit Reveal_* rules for the Issuer key and victim holder key — neither of which the attack uses. The adversary's only key comes from an Adversary_Wallet_Key rule (its own freshly generated key). The Prerequisite Issuer is modelled as honest (it issues prerequisite credentials only to honest holders), so every issuance in the model is genuinely gated on a real honest-holder presentation.
We evaluated four configurations, labelled by their -D flag and mechanism:
Configuration (-D flag) |
Mechanism at the issuance step | Holder-binding confusion (A1) | Headline impersonation lemma | Honest-flow executability |
|---|---|---|---|---|
VULNERABLE (spec as written) |
none — no link between k_pres and k_proof |
breaks | falsified | verified |
FIXED_NONCE (nonce-bound key proof) |
key proof must carry the auth_session nonce |
still breaks | falsified | verified |
FIXED (holder-key continuity) |
Issuer requires k_proof = k_pres (issued key ≡ accepted presentation's holder key) |
closed | verified | verified |
FIXED_TXDATA (presenter commitment) |
presenter commits h(k_iss) inside the KB-JWT; Issuer checks the key proof's key against the commitment |
closed (permits key separation) | verified | verified |
Per-configuration lemma verdicts (Tamarin 1.12.0; all four pass well-formedness):
- All configurations:
ltkCI_secrecy,skH_secrecy,holderkey_unique, andexec_honest_iae_flow(executability) — verified. VULNERABLE:a1_attack_witness(concrete, zero-compromise PoC) — verified;a1_holder_continuity_vulnanda1_no_impersonation— falsified.FIXED_NONCE:a1_no_impersonationanda1_holder_continuity_nonce— falsified.FIXED:a1_no_impersonationanda1_holder_continuity_fixed— verified.FIXED_TXDATA:a1_no_impersonationanda1_holder_authorization_txdata— verified.
The headline property, a1_no_impersonation (stated identically across all configs), is: no credential is ever issued bound to an adversary-controlled key while gated on an honest, un-revealed victim's presentation.
Key findings from formal verification
-
The gap is structural, not a textual ambiguity. Under
VULNERABLEthe confusion constructs with no creative reasoning — and it does so even without any adversary key:a1_holder_continuity_vulnis falsified by a trace in which the issued credential is bound to a second honest holder's key while the presentation was the victim's, with no compromise anywhere. The portability of the key proof (it binds only(CI, pkH), never the session or the presenter) is the root cause. -
a1_attack_witnessis a clean, zero-compromise proof-of-concept. Tamarin returns a trace in which the credential is issued bound to the adversary's key, carries the victim's subject, and is read by the adversary (K(cred)), with noReveal_CIand noReveal_HolderKeyanywhere in the trace — the adversary uses only its ownAdversary_Wallet_Key. This confirms the attack is a property of the baseline protocol, not of any key leak. -
§6.2.1.4's nonce binding does not help — and the obvious patch (
FIXED_NONCE) fails for a non-obvious reason. Binding theauth_sessionnonce into the issuance key proof and checking equality is a natural first fix. Formal analysis falsifies it: the nonce ships in the clear in therequire_interactionresponse, so any party freshly mints a key proof over its own key carrying that nonce. The underlying argument is general and deductive — a freshness value the Issuer hands out in the clear carries no requester identity, so wrapping it into a proof cannot constrain who chose the key. The binding must come from material the Issuer already knows belongs to the presenter. -
FIXED(continuity) andFIXED_TXDATA(commitment) both close the attack, at the right layer.FIXEDmakes the Issuer enforcek_proof = k_pres: in the impersonation trace this forcespk(skH_Adv) = pk(skH_pres), impossible for distinct fresh keys (a1_no_impersonationcloses immediately).FIXED_TXDATAinstead has the presenter commit to the intended issuance keyh(k_iss)inside the KB-JWT (signed by the presenter's holder key); the proof discharges the cuckoo branch via a KB-JWT-origin argument — the only producer of that commitment is the genuine presenter committing to its own fresh key, and forging it would require the victim's holder key.FIXED_TXDATAthereby closes the attack while still allowing the issued key to differ from the presented key (k_iss ≠ k_pres), preserving per-credential key unlinkability.
Model, configurations, and proof artifacts: https://github.com/congenial-max/OpenID4VCI_v1-1_IAE_cross-session-holder-binding-confusion_FormalSecurityAnalysis/tree/8971275293bc75d3a5c7e441c7f73e4e5835a5b3
Recommended Fix: Bind the Issued Holder Key to the Accepted Presentation
The Credential Issuer must, at the issuance step, cryptographically tie the holder key of the issued credential to the holder that produced the accepted presentation. We verified two interoperable options; either closes the attack, and the choice is a privacy-vs-simplicity tradeoff.
Option A — holder-key continuity (FIXED). The Issuer requires the issuance key proof to verify under, and the credential to be bound to, the same holder key that signed the accepted VP's KB-JWT, and rejects otherwise. Simplest to specify and implement; the cost is that the issued credential is bound to the same key as the presented one.
Option B — presenter-signed key commitment (FIXED_TXDATA), recommended where key separation matters. The presenting holder commits, inside the KB-JWT it already signs, to a thumbprint h(k_iss) of the (possibly fresh) key the new credential should be bound to — naturally carried via the OpenID4VP transaction_data mechanism. The Issuer verifies that the key in the issuance key proof matches that commitment. This closes the attack and permits k_iss ≠ k_pres, so a Wallet can bind each issued credential to a fresh key for unlinkability without weakening the binding.
Why neither nonce-binding nor a key-proof extension suffices
- Nonce-binding the key proof (
FIXED_NONCE) does not work: the nonce is public, so it is re-mintable over an attacker-chosen key (falsified; see Key Finding 3). - More generally, no extension of the key proof's own payload can fix this, because the key proof is signed under the issuance key, which the adversary chooses and controls. Any payload an adversary-held key can sign, an adversary-held key can re-sign. The binding must reference the presenter's key (Option A) or a presenter-signed commitment (Option B) — material outside the issuance key's control.
Why this is the right fix
- It moves the binding to where the threat model places trust. The gap is precisely that the Issuer trusts the presentation (presenter's holder key, in the device-side trust domain) but binds the credential to an unrelated, freely-chosen issuance key. Both options re-anchor the binding on the presenter's holder key, which the §13.4 backend compromise does not reach.
- It is standards-aligned, not bespoke. Option B reuses OpenID4VP
transaction_dataand the KB-JWT the holder already produces; both options use only JWS over JSON and add no new primitives or endpoints. It makes the existing companion-document requirements I-40 / P-50 protocol-enforced for this path. - It composes cleanly. The Issuer's added check is a single JWK comparison (Option A) or one hash/commitment comparison (Option B); no new token types and no change to the synchronous flow.
Spec changes required
-
§6 / §6.2.1 (issuance after presentation): Add normative text requiring the Credential Issuer to bind the holder key of the issued credential to the holder that produced the accepted presentation, via either:
- (Option A) requiring the issuance key proof to verify under the same holder key as the accepted VP's KB-JWT, and rejecting the Credential Request otherwise; or
- (Option B) requiring the accepted KB-JWT to carry a commitment (e.g.
transaction_datacontainingh(k_iss)) to the intended issuance key, and requiring the Issuer to verify the key proof's key against that commitment.
On mismatch the Issuer MUST reject with HTTP 400 and an appropriate error (e.g.
invalid_proof, or a newholder_binding_mismatchvalue). -
§6.2.1.4 (Preventing Session Fixation Attacks): Add a clarifying note that the
nonce ↔ auth_sessionassociation prevents session fixation but does not establish holder-key continuity across the presentation→issuance boundary; the binding in (1) is additionally required. -
Appendix A.2.5 / A.3.5 (Holder-Binding audience): Note that the
iar:audience binds the VP to the Issuer endpoint but not to any issuance key; cross-reference (1). -
§13 (Security Considerations): Document this cross-session holder-binding confusion and its §13.4 split-architecture instantiation, and state explicitly that TLS confidentiality and signature unforgeability do not prevent it (it is a binding failure). Note that the binding in (1) closes it without any assumption of key secrecy beyond the presenter's holder key.
-
§13.1 (Formal Security Analysis): Add a reference to this analysis under the existing list of formal-security-analysis citations.
-
Companion document mapping: Make holder-binding requirements I-40 / P-50 protocol-enforced for the IAE presentation-during-issuance path via (1).
Limitations of the fix and of the model
- Option A vs. unlinkability. Continuity (Option A) forces the issued credential's holder key to equal the presented one, which conflicts with fresh-
pkH-per-credential privacy patterns. Option B avoids this; deployments with a per-credential-key privacy model should prefer Option B. - Modelling abstractions. TLS is abstracted as Dolev–Yao channels; the OAuth/PAR + Token Endpoint is folded into one opaque, session-bound Access Token; DPoP is omitted (it sender-constrains the Access Token to the transport key, not the holder/issuance key, so it gives no uplift against this attack); credentials use carry-and-verify signing; a single derived-credential dataset is modelled.
- Honest Prerequisite Issuer. We model
PIas honest (issuing only to honest holders); a maliciousPIthat mints prerequisite credentials to attackers is a distinct, stronger compromise not covered here (and not required for this attack). - Batch issuance (the
proofsarray, multiple holder keys per request) is not modelled; the binding in (1) would need to apply per proof. We flag this as future work. - Full backend compromise. If the holder/commitment private keys themselves reside in (and are taken from) the compromised backend rather than the device-side trust domain, the binding in (1) reduces to the full-Wallet-compromise case, which no protocol can distinguish from the legitimate holder. The value of the fix derives precisely from the §13.4 boundary, where the holder key is not in the compromised backend.
Suggested Action
- Acknowledge the structural cross-stage holder-binding gap in §6 (presented holder key vs. issuance key proof) under the §13.4-acknowledged adversary, and that §6.2.1.4 does not close it.
- Adopt a binding at the issuance step — Option A (continuity) or Option B (presenter-signed commitment) — with Option B recommended where per-credential key separation/unlinkability is a goal.
- Update §6/§6.2.1, §6.2.1.4, Appendix A.2.5/A.3.5, §13, and §13.1 as described above.
- (Optional) Reference the Tamarin model and proofs from §13.1.
We recommend this be processed as part of the v1.1 work, since the IAE is a v1.1 addition. The change adds no new endpoints or token types: the new request members (an iar:-bound key commitment, or the continuity check) and the Issuer-side verification are additive.
We are happy to provide:
- A pull request against the spec text containing the §6 / §6.2.1.4 / Appendix A / §13 / §13.1 changes.
- The full Tamarin model and proof artifacts for all four configurations (
VULNERABLE,FIXED_NONCE,FIXED,FIXED_TXDATA), with a reproducibility README. - A walkthrough with working-group security reviewers if useful.
References
- OpenID for Verifiable Credential Issuance 1.1, editor's draft
openid-4-verifiable-credential-issuance-1_1-01(Lodderstedt, Yasuda, Looker, Bastian). - OpenID for Verifiable Presentations (for
transaction_dataand the KB-JWT holder-binding mechanism). - Fett, D., Lodderstedt, T. — Security and Trust in the OpenID4VC Ecosystem (companion document), holder-binding requirements I-40 and P-50.
- RFC 7800 — Proof-of-Possession Key Semantics for JWTs (related
cnfbinding). - RFC 7638 — JSON Web Key (JWK) Thumbprint.
- Basin, D., Cremers, C., Dreier, J., Sasse, R. — The Tamarin Prover for the Symbolic Analysis of Security Protocols.
Contributor guide
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.
Research direction
Start with §6 and §9 of the OpenID4VCI 1.1 editor's draft, then inspect the Tamarin theory OID4VCI_A1 and its a1_* lemmas. Compare the holder-key continuity and presenter-signed commitment configurations described in the issue. Done means adopting a specified binding that prevents the cross-session attack and preserves the claimed security properties in the formal model.
Written by the indexing model from the issue text.
Assessment
- Domain
- authentication, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100