Verification paths
Every Cocoon session produces two attestation quotes — one from cocoon-bridge (the SDK-facing TEE) and one from cocoon-proxy (the TEE behind it). They complement each other rather than form a strict chain, so different audiences can pick how much they want to verify themselves vs. how much they're willing to take on transitive trust.
This page lays out four workflows. Most teams use Path 1; the remaining paths are layered in for higher-assurance environments or auditors.
At a glance
Audience | Path | What you do | What you get |
|---|---|---|---|
Default user | SDK default policy | Use the SDK as-is. | Connection refused if |
Custom hashes | SDK custom policy | Set explicit | Pin to the exact builds you trust — both TEEs, independently of any SDK update. |
Reproducer | Standalone build + verify | Clone the open-source | First-hand evidence that the published image hashes correspond to the published source. |
Independent proxy check | Verify | Read the proxy quote from the session response and recompute the image hash without relying on | Defence-in-depth: even if |
You can stack paths — most teams start with the default policy in production and keep a reproducible-build pipeline in CI as ongoing evidence that the published hashes haven't drifted.
Path 1 — Default SDK policy
The SDKs ship with attestation verification on by default. There's nothing you have to opt into.
Go
TypeScript
What the default policy enforces, on every WebSocket session:
Parse the TDX quote returned by
cocoon-bridge.Verify
report_data == SHA-512(tee_session_pubkey)— the session key was minted inside this specific TEE.Recompute the image hash from the quote's measurement registers and check it against the SDK's built-in allowlist.
In production deployments, the gateway runs
cocoon-bridgewithTDX_VERIFICATION_MODE=dcap, which adds Intel DCAP signature verification of the quote against the Intel-rooted cert chain.
If any check fails, the SDK raises an attestation error before the first byte of plaintext leaves the client. No additional code is required.
Path 2 — SDK with a custom allowlist
If you've reviewed a specific build of cocoon-bridge (or reproduced it yourself — see Path 3), pin the SDK to that exact image hash so an SDK update can't silently broaden the set of accepted images:
Go
TypeScript
This is the correct posture for high-assurance environments: an SDK update bumping the default allowlist won't change which builds your client trusts. When you want to accept a new image, you add its hash yourself after reviewing or reproducing it.
To accept multiple builds during a rolling deployment (old + new hash side-by-side), pass both:
Path 3 — Reproduce the build yourself
Reproducing the cocoon-bridge image is the strongest available form of verification: it ties the hash you trust directly to source code you can read.
The two hashes will match if and only if no byte of the source you inspected differs from the byte that produced the released image.
Once you have a reproduced hash, add it to your AllowedCocoonProxyImageHashes (see Path 2) so your client only accepts that exact build. You've now closed the loop with no third-party trust:
The CPU signs the measurement (Intel TDX root of trust).
The measurement is the image hash (deterministic algorithm in the TDX spec).
The image hash matches a hash you produced from open source (your build, your machine).
Repeating this build in CI on every release gives you ongoing evidence that the published hashes correspond to the published source.
Path 4 — Verify the cocoon-proxy attestation independently
By default the SDK takes the proxy verification on transitive trust: cocoon-bridge refused to start unless the proxy's quote matched its TDX_ALLOWED_IMAGE_HASHES, so a running session implies a valid proxy. For auditors and high-assurance deployments that don't want to take that step on faith, the cocoon-proxy quote is exposed alongside the bridge quote in the session response — pull it and verify it directly.
The proxy quote uses the same TDX format as the bridge quote: the AttestationQuote struct in shroud-sdk-go/cocoon/attestation.go parses both. Running the same ImageHash() computation on the proxy quote yields a hash you can compare against your own AllowedCocoonProxyImageHashes list.
This is what the existing AllowedCocoonProxyImageHashes field on AttestationPolicy already does internally — set it explicitly to opt out of the SDK's shipped default and pin the proxy yourself:
Verifying the proxy quote independently doesn't replace bridge verification — it complements it. Both quotes go through the same DCAP signature check in production. The privacy claim holds with either quote alone; verifying both means a flaw in either TEE component is caught locally instead of cascading.
Don't do this
Don't skip attestation in production. A
null/WithAttestationPolicy(nil)client is a plain TLS connection to a TEE-shaped service. The privacy claim does not hold.Don't accept an image hash you haven't reviewed. Trusting an arbitrary hash because someone published it next to "verified TEE" is no stronger than trusting their server.
Don't pin against an empty allowlist. Both SDKs treat an empty
AllowedCocoonProxyImageHashesslice as "every quote passes" — it is intended for unit tests with mock attestation. Always pass at least one hash, or use the default policy.
Related
How attestation works — the four-step trust chain.
Threat model — what these checks do and don't protect against.