Skip to content

security: enforce E2EE/TEE conversation integrity client-side#24

Open
thistehneisen wants to merge 1 commit into
veniceai:mainfrom
thistehneisen:security/e2ee-response-integrity
Open

security: enforce E2EE/TEE conversation integrity client-side#24
thistehneisen wants to merge 1 commit into
veniceai:mainfrom
thistehneisen:security/e2ee-response-integrity

Conversation

@thistehneisen
Copy link
Copy Markdown

Summary

The E2EE / "TEE-attested" conversation guarantee was not enforced on the client. A malicious or compromised server could present attacker-authored content under the 🔐 Response decrypted end-to-end banner:

  • verifySignature() returned verified: true for any 64-hex signedText without checking the hash committed to the response (signature-bypass).
  • streamChat() displayed/trusted E2EE responses without ever fetching or verifying the enclave signature (fetchTeeSignature/verifySignature were dead code).
  • The isHexEncrypted() gate allowed a plaintext chunk to be shown verbatim while the CLI still asserted it was decrypted end-to-end.

This maps to conversation/chat encryption and privacy-control integrity.

Changes

  • src/lib/e2ee.ts: replace the hash short-circuit with real sha256(expectedContent) verification, constant-time compared (single-hash and request:response pair forms). Re-encoded UTF-16 → UTF-8 so the change is reviewable by git diff / SAST (the file previously showed as binary).
  • src/commands/chat.ts: in E2EE mode, reject non-ciphertext chunks, buffer decrypted content instead of streaming it unverified, and verify the TEE response signature against the attested signing address before any content is displayed or the banner is printed.

Known limitation / follow-up

This closes the integrity gap and the signature-bypass. It does not yet add client-side Intel PCK / NVIDIA NRAS quote-signature verification — the policy still trusts the server-reported server_verification.tdx.valid and the server-supplied signing key, so a malicious server can still substitute its own attested key (confidentiality). Tracked in SECURITY_PR.md; recommended as separate, larger work.

Test plan

  • npm run build passes
  • Non-E2EE streaming UX unchanged (token-by-token)
  • E2EE buffers then renders only after signature verification
  • Confirm the official web app and mobile/APK clients perform equivalent client-side verification

verifySignature() returned verified:true for any 64-hex signedText
without checking the hash committed to the response, and streamChat()
displayed/trusted E2EE responses without ever verifying the enclave
signature (fetchTeeSignature/verifySignature were dead code) while the
isHexEncrypted gate let plaintext through under the "decrypted
end-to-end" banner. A malicious or compromised server could therefore
present forged content as attested.

- e2ee.ts: replace the hash short-circuit with real sha256(content)
  verification, constant-time compared (single hash and request:response
  pair). Re-encoded UTF-16 -> UTF-8 so the change is reviewable by
  diff/SAST tooling.
- chat.ts: in E2EE mode reject non-ciphertext chunks, buffer decrypted
  content instead of streaming it unverified, and verify the TEE
  response signature against the attested signing address before any
  content is shown or the banner is printed.

Does not yet add client-side Intel PCK / NVIDIA NRAS quote
verification; see SECURITY_PR.md for the tracked follow-up.
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