TEE verification and encrypted inference
Verify enclave evidence and per-request receipts, understand verification levels, and use opaque NEAR or Chutes E2EE.
AnonRouter exposes provider-neutral enclave attestation and request-signature services. Provider evidence is fetched by a credential-isolated worker, verified fail-closed, and returned to you so your client can independently repeat the verification.
TEE is not automatically hardware-verified
A route's privacy modality and its verification level are separate claims. This
API never turns a provider boolean, model suffix, or confidential-compute flag
into silicon proof. No provider route (hop 2) currently reaches
hardware-verified: several run GPU enclaves whose NVIDIA chain is not
available to verify, and chaining only the CPU quote would claim more than was
checked.
Hop 1 — AnonRouter's own routing plane — is different, and is reachable at
hardware_verified with a DCAP engine. See
Verify AnonRouter itself.
Building an E2EE client?
Follow the dedicated E2EE client guide for the ticket sequence, provider wire formats, required headers, retry rules, and production checklist. This page remains the attestation and receipt reference.
Two hops, verified separately
A request passes through two parties, and verifying one tells you nothing about the other.
| Question it answers | How to check it | |
|---|---|---|
| Hop 1 — AnonRouter's own routing plane | Is the router I am talking to the exact reviewed build, running inside an Intel TDX confidential VM, bound to my nonce and my origin? | GET /v1/gateway/attestation — credential-free |
| Hop 2 — the downstream provider route | Did the model provider terminate my request inside a verified enclave running measurements I pinned? | the provider attestation and receipt APIs below |
A verified hop 2 says nothing about who routed the request there. A verified hop 1 says nothing about where inference actually ran. Most of this page is about hop 2; the section immediately below is hop 1.
Verify AnonRouter itself (hop 1)
AnonRouter's content plane runs inside an Intel TDX confidential VM. The relay, the compatibility broker, and every provider worker run inside that TD, and TLS terminates in-enclave rather than at a platform gateway in front of it.
This is why the privacy properties on the privacy page are not just policy. Prompts do not reach ordinary AnonRouter infrastructure, and no operator can read them off a running host — and you do not have to take that on trust, because the plane will attest to itself on demand.
The endpoint
NONCE=$(openssl rand -hex 32)
curl -s "https://api.anonrouter.ai/v1/gateway/attestation?nonce=$NONCE"GET /v1/gateway/attestation is credential-free — a client should be able to
check the plane before trusting it with anything, including before it has an
account. The nonce is required and must be exactly 64 hex characters (32
bytes); a request without one is a 400.
The response is a JSON document of roughly 95 KB:
| Field | What it carries |
|---|---|
binding | the claims being attested: your nonce, app_id, instance_id, compose_hash, release_id, origin, the plane's public_key, transport, and tls_spki_sha256 |
binding_hash | the digest committed into the quote's report_data |
quote | the raw Intel TDX quote |
event_log | the boot event log, which replays to the quote's RTMRs |
app_compose, vm_config | the measured deployment definition |
issued_at_ms | freshness |
What a verdict establishes
Verifying that document is what turns "AnonRouter says it runs in an enclave" into something you checked:
- the quote is fresh and yours — your nonce appears inside the quote's
report_data, as the digest of the canonical binding, so a recorded response cannot be replayed at you; - TLS terminates inside the TD —
binding.transportisin-tee-tls, notgateway-tls. There is no platform proxy in front of the enclave holding your plaintext; - the certificate belongs to the attested TD — the leaf SPKI you observed on
your own connection equals
binding.tls_spki_sha256. This is the check that turns "somebody named a certificate" into "the enclave holds the key for this connection"; - the build is the reviewed one —
compose_hash,app_id,release_idand the platform measurements match pins you hold locally, not values the server chose; - the event log is consistent — it replays to the quote's RTMRs.
The pins must not come from the server being checked
A server that could hand you the list of builds you accept could always name itself. Hold the plane to measurements you obtained independently. The SDK ships reviewed pins inside the package for exactly this reason, and fails rather than falling back to whatever the origin claims.
Checking it without writing a verifier
Both SDK packages install anonrouter-verify, which does the whole document and
exits nonzero unless the assurance you asked for held:
anonrouter-verify gateway --origin https://api.anonrouter.ai \
--dcap --require hardware_verified
echo $? # 0 met, 1 not met, 2 the command was wrongHop 1 is the one place a hardware_verified result is reachable, and only with a
DCAP engine that actually chained the quote's ECDSA signature to Intel's roots
with an accepted TCB status. Without an engine the honest ceiling is
cryptographically_checked, and a policy demanding hardware verification fails
closed rather than quietly settling for less. See the
SDK verification guide and the
command reference.
The pin SDK v0.1.0 ships is older than the running plane
A shipped pin is a snapshot of a reviewed release, and the content plane has
been released since v0.1.0 was tagged. The pin in that version names the
previous build, so the command above fails closed against production today
on compose_hash_pinned and release_pinned rather than passing. That is the
design working — the alternative would be an SDK that accepts whatever the
origin currently claims — but until a refreshed pin ships, gate on a policy you
reviewed yourself with --policy. Check the running build's compose_hash
and release_id against the release you reviewed.
What hop 1 does not cover
- It says nothing about the provider. That is hop 2, below.
- It does not make a TEE route end-to-end encrypted. Inside the enclave, the relay handles your plaintext to route and meter it. What that buys you is that a build changed to exfiltrate it would change the measurements and stop verifying — cheating is detectable, not impossible. Only an E2EE route keeps content opaque to AnonRouter's build whatever code it is running.
- It says nothing about what the provider does with the prompt. On an ordinary route the worker forwards plaintext to the upstream provider, which sees it under that provider's own policy. Check the privacy label on the route.
- Attestation names the build; it does not review it. Reading the source behind a pinned compose hash is a separate act.
Support matrix
| Provider | Maximum verification | AnonRouter modality | Per-request receipt |
|---|---|---|---|
| Chutes confidential text | provider-attested | Non-streaming ML-KEM whole-body e2ee | Not exposed by the provider; returns tee_signature_not_supported |
| Tinfoil | sdk-verified | tee over TLS/JSON | Not exposed by the provider; returns tee_signature_not_supported |
| Venice | provider-attested | e2ee | EIP-191 enclave receipt for completed non-stream and streaming requests |
| NEAR AI direct | provider-attested | Opaque e2ee, version 2 | EIP-191 receipt with exact AnonRouter wire-hash binding for completed non-stream requests |
| NEAR AI attested-3p | No direct model-enclave attestation | tee | No receipt through the direct flow |
NEAR AI has no callable route in the current catalog
The NEAR verifier and the version 2 opaque protocol below are implemented and
documented, but the live catalog publishes no callable NEAR AI route. Every
NEAR example on this page is therefore a protocol reference rather than a
request you can run today. Read
GET /v1/catalog/models for what is actually
callable before pinning a provider.
The confidential routes the catalog publishes as callable today are Tinfoil
tee, Venice e2ee, and Chutes e2ee. Chutes' callable routes are text-only;
the one callable embedding route is Tinfoil's nomic-ai/nomic-embed-text, which
is tee rather than e2ee.
Tinfoil documents EHBP/HPKE transport, but its model selector is encrypted and the documented outer headers do not bind that model to an AnonRouter ticket or reservation. AnonRouter fails closed rather than expose a proxy through which a caller could ticket one model and encrypt a request for another. Tinfoil routes are therefore not advertised as E2EE.
Verification levels
| Level | What the result proves |
|---|---|
hardware-verified | Quote signatures, certificate and revocation chains, acceptable TCB, GPU evidence, nonce and key bindings, debug state, and pinned measurements all passed to silicon-vendor trust roots. No provider route reaches this level; AnonRouter's own plane (hop 1) does, with a DCAP engine. |
sdk-verified | The official provider SDK completed its required cryptographic verification and the result matched AnonRouter's pinned release policy. |
provider-attested | Required structure, freshness, nonce/key, route, certificate-possession, and pinned-measurement checks passed, but the complete silicon-vendor chain was not independently established. |
unverified | A required check, policy value, or evidence item was absent or failed. |
unsupported | The selected provider or route does not expose the requested capability. |
The Intel/NVIDIA chain port remains intentionally unwired. The currently
available path does not provide all collateral, trust-root, revocation, and TCB
handling needed to make the stronger claim. Incomplete evidence fails closed at
provider-attested or unverified.
Fetch fresh attestation evidence
Both public TEE endpoints require an API key with the inference scope. Use a
fresh random nonce containing 32 to 64 bytes, encoded as hexadecimal:
curl "https://control.anonrouter.ai/v1/tee/attestation?model=openai/gpt-oss-120b&provider=tinfoil&nonce=$NONCE" \
-H "Authorization: Bearer $ANONROUTER_API_KEY"The same evidence is available from the confidential origin without presenting a key to it, using an attestation ticket instead.
The response identifies the exact provider route and privacy modality and contains:
verification_leveland every individual check;- normalized measurements and public signing identities;
- the measurement-policy version and expiry;
- the exact raw provider evidence for independent client verification.
Attestation results are cached for five minutes without prompts, responses, private keys, or raw request bodies. A hostname or model name alone never earns a verification level.
Retrieve a request receipt
After a supported completion, use the provider's request ID returned with that completion:
curl "https://control.anonrouter.ai/v1/tee/signature/$PROVIDER_REQUEST_ID?model=z-ai/glm-5.2&provider=venice" \
-H "Authorization: Bearer $ANONROUTER_API_KEY"Optional request_hash and response_hash query parameters are additional
client cross-checks. They never replace the content-free hashes calculated and
stored by AnonRouter.
NEAR exact-wire receipts
For a non-stream request, the credential worker hashes the exact JSON sent to the direct enclave and the exact raw response before parsing. Receipt lookup requires an unexpired route binding, a fresh matching attestation, exact hash equality, and successful EIP-191 recovery to the attested signing address.
For a verified NEAR receipt, hash_binding_checked: true means the signed
request and response hashes equal the exact bytes observed by AnonRouter. NEAR
streaming does not yet provide the completed-response binding needed for this
claim and fails with tee_signature_binding_unavailable.
Venice enclave receipts
Venice receipts are recovered with EIP-191 against the secp256k1 key committed
to the earlier TDX attestation. The signed statement, completion ID, model, and
request.received/response.returned event hashes must agree.
Venice signs an enclave-internal ingress/egress representation rather than the
exact public API wire bytes. A valid receipt therefore normally returns
verified: true, verification_level: "provider-attested", and
hash_binding_checked: false. The response exposes both bound_* provider
hashes and gateway_* wire hashes instead of claiming equality Venice did not
sign.
Completed Venice streams are supported. Receipt metadata crosses the worker boundary in a private sideband that is never emitted as a customer SSE event. Aborted or incomplete streams produce no signature binding.
Unsupported is not a broken TEE route
Chutes and Tinfoil inference and public attestation work normally. They do not
expose a compatible per-completion receipt, so signature lookup returns the
structured 501 tee_signature_not_supported response. AnonRouter never
fabricates a substitute gateway signature.
NEAR v2 opaque E2EE
NEAR direct routes expose the provider-neutral v2 field-encryption modality. Request a nonce-bound attestation ticket for the exact direct route, then send ciphertext with this validated header set:
X-AnonRouter-E2EE-Provider: near-ai
X-Signing-Algo: ed25519
X-Client-Pub-Key: <32-byte Ed25519 public key as 64 lowercase hex chars>
X-Encryption-Version: 2Do not send X-Model-Pub-Key. That field belongs to NEAR's cloud gateway;
AnonRouter obtains the model key from the direct enclave's attestation.
For every encrypted field, the client uses ephemeral X25519 ECDH and
HKDF-SHA256 with info = "ed25519_encryption", then encodes this lowercase-hex
wire value:
[ephemeral X25519 public key: 32 bytes]
[XChaCha20-Poly1305 nonce: 24 bytes]
[ciphertext + authentication tag]Encryption and decryption stay client-side. AnonRouter forwards only the validated headers and opaque ciphertext, does not parse message fields as plaintext, and never receives either private key.
Endpoint discovery must exactly match the reviewed direct enclave domain.
Missing or mismatched discovery fails with
e2ee_enclave_endpoint_unavailable; an E2EE request never falls back to the
cloud gateway, a plaintext route, or another provider.
Chutes ML-KEM whole-body E2EE
Confidential Chutes text routes are ciphertext-only through AnonRouter. First,
use the normal model-bound attestation-ticket flow. The returned raw evidence
contains e2e_instances: instance UUIDs, ML-KEM-768 public keys, and short-lived
single-use nonces. Accept a key only after verifying the response and its
SHA256(caller nonce || ML-KEM key) TDX report-data commitment.
Encrypt with Chutes' official transport format, then submit the exact bytes:
curl "https://api.anonrouter.ai/v1/e2ee/chat/completions" \
-X POST \
-H "Content-Type: application/octet-stream" \
-H "X-AnonRouter-Ticket: $INFERENCE_TICKET" \
-H "X-AnonRouter-E2EE-Provider: chutes" \
-H "X-Chutes-Instance-Id: $ATTESTED_INSTANCE_ID" \
-H "X-Chutes-E2E-Nonce: $SINGLE_USE_NONCE" \
--data-binary @encrypted-request.bin \
--output encrypted-response.binThe credential worker resolves the ticket-bound model to its live chute_id,
requires confidential_compute: true, overwrites the chute, path, and streaming
headers, and adds the Chutes credential. Only the two validated instance/nonce
values cross from the client. Request and response bodies remain byte-for-byte
opaque to AnonRouter, and there is no provider fallback.
This first endpoint is non-streaming. Chutes keeps its non-stream token usage
inside the encrypted response, so the ticket must reserve the model's full output
ceiling. AnonRouter reserves the full context at the most expensive token rate
and conservatively captures it after success; it never estimates plaintext usage
from compressed ciphertext length. The ticket-mint request must therefore set
max_tokens to the model's published maximum.
The opt-in live suite performs a real ML-KEM-768 request/response round trip and decrypts only in the test client; the relay receives only the encrypted blobs.
What each provider check establishes
Chutes
AnonRouter checks every returned instance: TDX v4 structure and debug state,
pinned MRTD/RTMR0-3 measurements, the nonce plus ML-KEM key commitment, the
certificate SPKI commitment, RSA possession of the decoded attested body,
inner/outer quote and GPU equality, certificate validity, and complete instance
key discovery. The missing complete Intel/NVIDIA vendor chain keeps the result
at provider-attested. For an e2ee result, the verified ML-KEM key commitment
also has to pass; the route never claims hardware-verified.
Tinfoil
The credential worker runs the official tinfoil@1.2.1 verifier. An
sdk-verified result requires securityVerified === true, all five SDK
verification steps, the selected endpoint, and exact pinned release digest,
code fingerprint, enclave fingerprint, and TLS key. A missing SDK or document
never defaults to success.
NEAR direct
AnonRouter checks TDX v4 structure and debug state, NVIDIA evidence, the
nonce/key/TLS commitment, exact model and direct endpoint, mr_config_id, the
serialized app_compose hash, and pinned MRTD/RTMR0-3 measurements for that
model. Current evidence does not independently prove the model-weight digest or
complete silicon chain, so the maximum remains provider-attested.
Venice
AnonRouter checks TDX v4 structure and debug state, caller nonce and model,
NVIDIA evidence, nested report-data equality, and a secp256k1 public key whose
derived address matches the signer committed into TDX report data. Venice's own
verified boolean is not accepted as proof.
Where a Venice E2EE route actually decrypts
E2EE guarantees that only the enclave you verified and encrypted to can read
the prompt. On some Venice routes that enclave is a verified gateway rather
than the machine running the model: it decrypts your request and forwards the
plaintext onward inside Venice's own infrastructure. The attestation is real
and AnonRouter still never sees plaintext, but "only the model host can read
it" is a stronger claim than the evidence supports. The catalog states this per
route in privacyNotes; read it before treating an E2EE label as a
model-host guarantee.
Phala AI
Phala AI is classified private, not confidential, and appears in no
two-hop count. It is an aggregator gateway that decrypts before forwarding, so
it carries no route attestation and no receipt. Do not read the provider's name
as a TEE claim; the route's own privacy label is the claim.
Service-level comparison
AnonRouter provides the core public operations documented by NanoGPT's TEE verification and signature APIs: fresh authenticated evidence, raw evidence for client verification, measurements and signing identities, and provider receipt lookup. AnonRouter also enforces explicit verification-strength levels, pinned measurement policies, route bindings, server-side EIP-191 recovery, and exact wire-hash checks where the provider signs those bytes.
The distinction is capability-specific: NEAR direct and Venice expose cryptographically verifiable request receipts, while Chutes and Tinfoil expose attestation without a compatible per-request receipt.
Trust boundaries
- The relay, the compatibility broker and every provider worker run inside the Intel TDX confidential VM, which terminates TLS in-enclave. Prompts do not reach ordinary AnonRouter infrastructure, and the plane attests to that on demand (hop 1).
- Provider credentials stay on their provider-specific worker.
- Control receives only content-free metadata; it serves no request content at
all, and answers
404for/v1/chat/completions. - Raw prompts, responses, API keys, decrypted E2EE content, and unsafe upstream bodies are never written to verification caches or logs.
- The dispatch fence still runs immediately before billable provider work.
- Measurement-policy changes require reviewed immutable pins rather than trusting a live provider assertion in place.
See the E2EE client guide, models and privacy labels, intelligent routing, and the complete privacy architecture for how these capabilities affect route selection and the rest of the request lifecycle.
Or hand the whole thing to your agent
One prompt carries the entire setup. Give it to your agent, review what it configures, and you are done.