Validate the e2ee public key against TDX attestation
e2ee-proxy is the local proxy a client runs to get E2EE; this is a client-side
fix, no service change.
Gap in the attestation chain
The proxy fetches the instance's e2ee public key from /e2e/instances and
encrypts to it without validating it against the TDX attestation. A compromised
or dishonest control plane can return a substituted key, and the proxy will
encrypt the prompt to it.
The binding already exists server-side: the enclave commits
report_data = SHA256(nonce + e2e_pubkey) in its TD quote (confirmed live). The
proxy just never checks it.
Fix
Before encrypting, validate the key against the quote:
- pick a nonce, fetch the quote (
/chutes/{id}/evidence?nonce=…);
- verify the DCAP signature;
- verify
report_data == SHA256(nonce + e2e_pubkey);
- verify non-debug and a pinned-allowlist MRTD.
Drop any instance that fails; if none pass, fail closed (no fallback to the
unverified key). Same checks as the verify_chute.py reference in the docs.
Changes
lua/e2ee_attest.lua (new) — nonce → fetch quote → verify
lua/e2ee_discovery.lua — cache a key only after it verifies
lua/e2ee_crypto.lua + native/e2ee_proxy_api.{c,h} — DCAP signature check
Dockerfile / build_protected.sh — Intel DCAP library
tests/test_attestation.py — checks the binding against live evidence
Settings
CHUTES_GOLDEN_MRTD — accepted MRTD(s); required, from a source you trust
(signed release / reproducible build), not the API.
CHUTES_DISABLE_ATTESTATION=true — explicit opt-out, like ALLOW_NON_CONFIDENTIAL.
Tested
Against live Qwen3-32B-TEE evidence, report_data matched
SHA256(nonce + pubkey) at the expected offset, with debug off and a consistent
MRTD across instances — so the binding/parsing is correct against production. The
DCAP signature path builds through the protected toolchain and still needs your
CI / a TEE host.
Scope
Stops key substitution. Does not address whether the serving code inside a
genuine enclave is measured — separate, server-side.
I have a working branch implementing this and can open a PR.
Validate the e2ee public key against TDX attestation
e2ee-proxyis the local proxy a client runs to get E2EE; this is a client-sidefix, no service change.
Gap in the attestation chain
The proxy fetches the instance's e2ee public key from
/e2e/instancesandencrypts to it without validating it against the TDX attestation. A compromised
or dishonest control plane can return a substituted key, and the proxy will
encrypt the prompt to it.
The binding already exists server-side: the enclave commits
report_data = SHA256(nonce + e2e_pubkey)in its TD quote (confirmed live). Theproxy just never checks it.
Fix
Before encrypting, validate the key against the quote:
/chutes/{id}/evidence?nonce=…);report_data == SHA256(nonce + e2e_pubkey);Drop any instance that fails; if none pass, fail closed (no fallback to the
unverified key). Same checks as the
verify_chute.pyreference in the docs.Changes
lua/e2ee_attest.lua(new) — nonce → fetch quote → verifylua/e2ee_discovery.lua— cache a key only after it verifieslua/e2ee_crypto.lua+native/e2ee_proxy_api.{c,h}— DCAP signature checkDockerfile/build_protected.sh— Intel DCAP librarytests/test_attestation.py— checks the binding against live evidenceSettings
CHUTES_GOLDEN_MRTD— accepted MRTD(s); required, from a source you trust(signed release / reproducible build), not the API.
CHUTES_DISABLE_ATTESTATION=true— explicit opt-out, likeALLOW_NON_CONFIDENTIAL.Tested
Against live
Qwen3-32B-TEEevidence,report_datamatchedSHA256(nonce + pubkey)at the expected offset, with debug off and a consistentMRTD across instances — so the binding/parsing is correct against production. The
DCAP signature path builds through the protected toolchain and still needs your
CI / a TEE host.
Scope
Stops key substitution. Does not address whether the serving code inside a
genuine enclave is measured — separate, server-side.
I have a working branch implementing this and can open a PR.