Today both e2ee clients trust enclave pubkeys on first use:
near_e2ee.ts getKey() fetches GET /attestation/report?model=…&signing_algo=ecdsa and takes model_attestations[].signing_public_key straight out of the response — the attestation evidence in that same report is never checked.
chutes_e2ee.ts instance() takes e2e_pubkey (+ nonce) from instance discovery, unverified.
So a compromised/MITM'd provider control plane could hand us a key that lives outside any enclave, and we'd encrypt the room's words to it. Verification means:
- NEAR (TDX+H100): verify the DCAP/TDX quote chain in the attestation report, check
report_data actually binds signing_public_key, check measurements against expected values, and verify GPU evidence (NRAS) for the H100 side.
- Chutes (NVIDIA CC): verify the instance attestation binding
e2e_pubkey, with nonce freshness.
Where it goes. Two options:
- Inline in the two client files, per app. Quick, but every sibling app on the pod duplicates it.
- Normalize at the pod level: the webhost already normalizes inbound trust (dstack: domain bound to attested app identity, keys derived only in the enclave) — do the same for outbound provider enclaves. One verifier on the tee-daemon (or a bitrouter-attestation role) verifies quotes once, pins the keys, and exposes a verified-key registry to sibling apps (goodpoint-box, interleave, otterpilot). dstack's own attestation stack doesn't cover this direction, but the same DCAP verification dependency (e.g. dcap-qvl) can be reused.
Leaning (2) — it's the same move dstack webhost already made for inbound trust, and it makes "verify the quote chain" a property of the pod rather than a chore for each app.
Acceptance: a forged/unattested pubkey is rejected in a test; verified keys cached with expiry + re-attestation; both providers covered.
Split (operator, 2026-08-16): the NEAR half now lives in #146 with its own ## Acceptance (delivered by PR #106; the merge gate closes #146, not this issue). What remains HERE: the Chutes (NVIDIA CC) half — verify the instance attestation binding e2e_pubkey with nonce freshness, dropping TOFU in chutes_e2ee.ts — plus the pubkey-cache expiry + re-attestation follow-up (the NEAR cache added in #106 is process-lifetime). This issue stays open with needs-spec until the remaining half is written up.
Today both e2ee clients trust enclave pubkeys on first use:
near_e2ee.tsgetKey()fetchesGET /attestation/report?model=…&signing_algo=ecdsaand takesmodel_attestations[].signing_public_keystraight out of the response — the attestation evidence in that same report is never checked.chutes_e2ee.tsinstance()takese2e_pubkey(+ nonce) from instance discovery, unverified.So a compromised/MITM'd provider control plane could hand us a key that lives outside any enclave, and we'd encrypt the room's words to it. Verification means:
report_dataactually bindssigning_public_key, check measurements against expected values, and verify GPU evidence (NRAS) for the H100 side.e2e_pubkey, with nonce freshness.Where it goes. Two options:
Leaning (2) — it's the same move dstack webhost already made for inbound trust, and it makes "verify the quote chain" a property of the pod rather than a chore for each app.
Acceptance: a forged/unattested pubkey is rejected in a test; verified keys cached with expiry + re-attestation; both providers covered.
Split (operator, 2026-08-16): the NEAR half now lives in #146 with its own
## Acceptance(delivered by PR #106; the merge gate closes #146, not this issue). What remains HERE: the Chutes (NVIDIA CC) half — verify the instance attestation bindinge2e_pubkeywith nonce freshness, dropping TOFU inchutes_e2ee.ts— plus the pubkey-cache expiry + re-attestation follow-up (the NEAR cache added in #106 is process-lifetime). This issue stays open withneeds-specuntil the remaining half is written up.