Skip to content

fix: SKR debug gate per attestation type; ComputeID receipt claims from the signed payload - #243

Merged
imran-siddique merged 2 commits into
mainfrom
fix/skr-debug-and-computeid-receipt
Sep 30, 2026
Merged

imran-siddique merged 2 commits into
mainfrom
fix/skr-debug-and-computeid-receipt

Conversation

@imran-siddique

Copy link
Copy Markdown
Member

Fixes GHSA-h8c4-mjgc-w25m and GHSA-8vvv-28gh-rr4v.

build_release_policy in integrations/wcm-azure-skr writes an Azure Key Vault secure key release policy from a Weight Custody Manifest. With require_not_debuggable, the debuggable check was added only when the first entry of required_hw_platform was amd-sev-snp (wcm_azure_skr.py:238).

  • ["intel-tdx", "amd-sev-snp"]: neither the tdxvm nor the sevsnpvm branch carries a debug condition, so Key Vault releases the key to a debug guest.
  • ["amd-sev-snp", "intel-tdx"]: the tdxvm branches get SNP-only claims (x-ms-sevsnpvm-is-debuggable, x-ms-sevsnpvm-hostdata), never match, and fail closed.

A debug guest lets the host read guest memory, so the released key is exposed to the host.

Fix: each anyOf branch is built from its own attestation type. sevsnpvm branches require x-ms-sevsnpvm-is-debuggable == false, tdxvm branches require tdx_td_attributes_debug == false (Microsoft Learn, TDX EAT profile). A TEE-specific measurement claim on the other TEE's branch is refused, and the TDX measurement claims are refused for a 64-hex WCM digest. evidence_from_maa_claims checks the debug claim for the token's own type.

Affected: integrations/wcm-azure-skr from cf9c1c1 (2026-08-27) to 59c9019. Regenerate any release policy built from a manifest that lists intel-tdx first. CWE-693.


offline-verifier.js in integrations/computeid-agentpassport-trace returns overall_pass=true for a bundle nobody issued. It verifies the CA signature over verification_receipt.receipt_payload but never parses that payload.

  • Freshness comes from the unsigned verification_receipt.expires_at.
  • Revocation comes from the unsigned bundle status.
  • The passport RSA and ML-DSA keys are taken from the bundle itself, and the receipt signs no passport key.

Reproduction on 59c9019:

  • The shipped evidence/opaque-diligence-demo.json gives overall_pass=false (expired). Changing only verification_receipt.expires_at to 2099 gives overall_pass=true.
  • A bundle with a new RSA key, passport_id=attacker-passport, capabilities ["admin"] and a CA receipt copied from another passport gives overall_pass=true with every outcome true.

Fix: passport_id, status, issued_at, expires_at and key_id are read only from the CA-signed receipt_payload and must equal the bundle and the unsigned copies. The signed key_id must name the supplied CA key. Passport keys count as trusted only when the signed payload carries public_key and pq_public_key equal to the bundle's.

Current ComputeID receipts do not sign the passport keys, so every bundle now reports issuer_trusted=false until the receipt format adds them. That is intended.

Affected: integrations/computeid-agentpassport-trace from 2d8144e (2026-09-10) to 59c9019. CWE-345.

Generated with Claude Code

imran-siddique and others added 2 commits September 30, 2026 13:16
The debug gate and base conditions were derived from
required_hw_platform[0]. With [intel-tdx, amd-sev-snp] no branch had a
debuggable gate; with [amd-sev-snp, intel-tdx] the tdxvm branches got
x-ms-sevsnpvm-is-debuggable and x-ms-sevsnpvm-hostdata, which MAA never
issues on a tdxvm token, so they never matched.

Each branch now gets its own gate: x-ms-sevsnpvm-is-debuggable on
sevsnpvm, tdx_td_attributes_debug on tdxvm (MAA TDX EAT profile and the
tdxvm sample token on the MAA token examples page). A TEE-specific
measurement claim is refused for the other TEE's branch; a mapping from
attestation type to claim is accepted instead. Documented TDX
measurement claims are added with their widths, so the width check
refuses them for a 64-hex WCM measurement. evidence_from_maa_claims
checks the debug claim of the token's own type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… CA-signed payload

offline-verifier.js checked the CA signature over receipt_payload but never
parsed it. Freshness used the unsigned receipt.expires_at, revocation the
unsigned bundle.status, and the passport keys are self-embedded, so an
edited expires_at, or an attacker bundle with its own keys and another
passport's genuine receipt, passed with overall_pass true.

passport_id, status, issued_at and expires_at now come only from the
verified receipt_payload and must equal the bundle and the unsigned
receipt copies; the signed key_id must name the supplied CA key. The
current receipt signs no passport key, so issuer_trusted and overall_pass
are false for every current ComputeID bundle, with the reason in
verification_reasons.receipt_binding. Output field names are unchanged;
receipt_binding, credential_fresh reasons and receipt_signed_fields are
added. verify() takes an optional now, the CLI --now, and node:test
tests cover the edited expiry, the attacker bundle and the fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@imran-siddique
imran-siddique requested review from a team and carloshvp as code owners September 30, 2026 22:47
@imran-siddique
imran-siddique merged commit 292f497 into main Sep 30, 2026
15 checks passed
@imran-siddique
imran-siddique deleted the fix/skr-debug-and-computeid-receipt branch September 30, 2026 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant