Attestation
Attestation and the evidence chain
What the evidence bundle contains, the six stages of the verification pipeline, how an unlisted root is admitted, the three verifying parties, and the boundary of what any of it proves.
ExplanationFor developers, users
This page describes what a verdict is made of, stage by stage. The commands that produce one are on Read a verdict; the deployments being verified are on Deployment topology.
The evidence bundle
The platform the router runs on serves a signed document for every endpoint at https://<hostname>/.well-known/swarm-evidence. The router relays a byte-identical copy at GET /v1/evidence so a browser can read it too. The document carries:
- a certificate chain ending in a Super Swarm root;
- a JSON Web Signature over the deployment snapshot: every container image by digest, and the configuration they run with;
- the fingerprint of the TLS certificate the endpoint serves;
issuedAt, re-signed every few minutes.
The SHA-256 of the canonical snapshot is the evidence digest. Pinning one says: this exact deployment, and no other. A redeploy with different images or a different configuration produces a different digest.
Every digest and measurement on this site is written as hex: sha256:<64 hex>. The document itself carries the wire form, sha256/<base64url>; Gatekeeper accepts both and prints hex.
The verification pipeline
Gatekeeper runs six stages, in order. Any failure is a denial that names the stage.
| Stage | What passes |
|---|---|
fetch | The endpoint served a bundle, over HTTP/1.1, with no redirects |
cert-chain | The bundle's chain validates from leaf to root |
untrusted-root | The root is one you listed, or it proves it is a Super Swarm root (below) |
jws | The signature verifies against the chain's leaf, and issuedAt is within the bundle age limit (24 hours by default) |
tls-fingerprint | The signed certificate fingerprint equals the leaf Gatekeeper saw on the very connection the bundle arrived over |
policy | The built-in pin policy and every policy of yours allow |
The fifth stage is what binds the deployment's claim to this connection. Gatekeeper never accepts a fingerprint the producer merely asserts; it compares against what it observed itself. It also ignores the operating system's trust store on purpose: trust is the chain terminating at a root you configured or Gatekeeper attested, plus that comparison.
Attested root certificates
A Super Swarm root certificate authority runs inside a confidential VM, and its certificate carries what that VM attested. When a chain ends in a root you never listed, Gatekeeper checks that evidence rather than giving up:
- The hardware report verifies against the CPU vendor's own root: AMD for SEV-SNP, Intel for TDX, with the certificates the evidence carries.
- The report commits to this certificate's public key, so the attestation is about this authority and not some other VM.
- The VM's launch measurement is rebuilt from Super Protocol's published build artefacts and has to reproduce what the hardware signed.
- That measurement carries a Super Protocol signature, checked against a key pinned in the Gatekeeper binary.
Step 4 is what closes the chain: without it, any tenant of any AMD or Intel host could produce steps 1 to 3. Roots enrolled on Azure confidential VMs go through the same four steps with one layer added for Microsoft's paravisor and the VM's virtual TPM. The check stays offline; Microsoft's attestation service is never consulted.
This is why the default setup has no certificate to paste. The production router's root is admitted this way; the report on Install and send a verified request shows attested (registry) and the measurement in trusted registry.
A measurement the registry has never signed is what a local or test build looks like. Test or unsigned builds covers that case.
The three verifying parties
The console chat also verifies, in the browser, and it says so in a badge. The three places a verdict can come from make three different claims and the product never blurs them:
| Tier | Who checks | What it proves | Badge |
|---|---|---|---|
| 1 | The console page, with code the deployment served | The deployment published a fresh, correctly signed bundle whose chain is valid and whose signed fingerprint matches the certificate it publishes | Verified by this page, with the caveat that this is self-reported |
| 2 | The Super Protocol browser extension | The same, by code the browser pinned from the web store and the deployment did not serve | Independently verified by the extension |
| 3 | Gatekeeper, on your machine | All of the above against the live TLS certificate, plus the launch measurement rebuilt from signed artefacts | Verify it yourself |
Tier 1 gates the chat composer: nothing is sent until it passes. Its badge is amber on purpose; the page came from the deployment it is judging, and it does not include the root check that decides whether Super Protocol vouches for the VM. Tier 3 is the only complete check, and the one production traffic should go through.
None of the three is the router asserting anything. Each is your own agent reporting what it did, to you: the answer is never sent to the router.
The boundary
What the router can see: request metadata (key id, model, timestamps, token counts, time to first token, client address, request id, whether it streamed), all of it metered and shown in the console; and prompt content in transit, inside TEE memory, forwarded to the model server and never written to the database, logs, metrics or error reports. That last property is part of the pinned snapshot, so it is verifiable rather than promised.
What the router cannot see, by construction: a verdict. There is no registration endpoint, no verdict header, no callback and no "verified" flag in any table, and the request Gatekeeper forwards is the one your client made, with its own headers stripped and no forwarding headers added, so no header reveals that a Gatekeeper is in the path. It also never verifies its own bundle and never holds a verdict about itself.
What is observable, said plainly because the opposite is easy to assume: fetching the evidence is an ordinary request to a published address, and it is as visible to whoever serves it as any other request. The platform's gateway serves /.well-known/swarm-evidence, not the router. So the claim worth making is not that nobody can tell the document was fetched. It is narrower and it holds: the verdict is formed on your machine, nothing reports it back, and neither the outcome nor your decision to go ahead is ever transmitted.
The header rule above does not extend to the connection underneath it either. Gatekeeper dials with Go's standard TLS stack and offers only HTTP/1.1, so a client fingerprint tells it apart from a browser or from curl. Defeating that kind of traffic analysis is not a goal of this design, and no page here should be read as claiming it.
What attestation proves: which code is running, that it runs on genuine TEE hardware, and that you are connected to it. What it does not prove: model quality, what happens to data on your side, or anything at all if you skip Gatekeeper. Without it your data is still protected; you have no proof.
Out of scope today: client-side validation of the platform's own quote field (rootCaTeeQuote reports not-implemented), GPU attestation, model-weight integrity beyond image digests, side channels inside the TEE, and denial of service. The full threat model is in the repository: docs/threat-model.md.