Private Mode: Browser-Encrypted TEE Requests on NanoGPT
NanoGPT now has Private Mode for supported TEE models in the web app.
This is different from simply routing a request to a TEE-backed model. In Private Mode, your browser verifies the TEE attestation path before sending the request, then sends the request body through an encrypted transport to the verified TEE target.
For API users, the same privacy boundary is available through a local OpenAI-compatible proxy. The important requirement is the same: encryption has to happen on your device before the request body reaches NanoGPT.
That gives users a stronger privacy boundary for supported text chats:
- the prompt body is encrypted before it leaves your browser
- the response body comes back through the same encrypted path
- NanoGPT can route and bill the request, but should not be able to read the prompt or completion body for that Private Mode request
- after the response, NanoGPT shows a verification receipt you can inspect, copy, and check independently
This post explains what this means, what it does not mean, and how to verify it yourself.
Short version
Private Mode is now available in the NanoGPT frontend for supported TEE text models.
When a model supports it, Private Mode is turned on by default for eligible chats. You can turn it off from the model selector if you prefer the normal route.
API clients can use Private Mode through the NanoGPT local proxy, which exposes a normal OpenAI-compatible /v1/chat/completions endpoint on your machine.
Private Mode currently works best for plain text chats. It is not enabled for chats that need extra plaintext context outside the encrypted request path, such as attachments, web search, project tools, scraped URLs, multi-model chats, image descriptions, or previous non-text/tool content.
Why this exists
We already had TEE models on NanoGPT. Those models improve the integrity and data-in-use story: the model can run inside a hardware-isolated environment, and attestation can prove something about the measured environment that handled the request.
But ordinary TEE routing is not the same thing as end-to-end encrypted prompt transport.
If a normal web or API request sends readable JSON to NanoGPT first, then NanoGPT can see that JSON before forwarding it. That may still be a useful TEE route, but it is not the strongest privacy boundary.
Private Mode is meant to close that gap for supported models:
Browser -> encrypted request -> verified TEE target
NanoGPT still sits in the operational path for authentication, routing, balance checks, and billing. The important difference is that the request and response bodies are encrypted before NanoGPT handles the private request.
What NanoGPT can still see
Private Mode does not make every part of the request invisible.
NanoGPT can still see information needed to operate the service, including:
| Category | Examples |
|---|---|
| Account and billing | your session or API key identity, balance state, usage, charges |
| Routing metadata | selected model, Private Mode status, TEE target metadata |
| Timing and reliability | request time, response time, success/failure state |
| Network metadata | ordinary HTTP metadata needed to receive and route the request |
| Usage metadata | token and cost data needed for billing |
The privacy improvement is narrower and concrete: for a successful browser-encrypted Private Mode request, NanoGPT should not be able to read the prompt body or completion body.
What NanoGPT should not be able to read
For a supported Private Mode request, NanoGPT should not be able to read:
- the prompt text inside the encrypted request body
- the assistant completion body returned through the encrypted response path
- the content of the encrypted body in ordinary server logs
That is why the feature is limited to eligible text chats for now. If a chat needs attachments, web search, project retrieval, scraped content, image descriptions, or tool messages, those data paths need separate privacy analysis. We do not want to silently claim those are protected when the encrypted path does not yet cover them.
How to use it
- Open the model selector.
- Choose a TEE model that shows Private Mode support.
- Private Mode will be on by default for eligible plain text chats.
- Send your message.
- After the assistant responds, click the shield icon in the message header to open the verification receipt.
If you turn Private Mode off for a specific model, NanoGPT remembers that choice for that model and will not keep turning it back on.
If a model does not show the Private Mode control, that model is not currently supported through the browser-encrypted Private Mode path. This is so far only working with Tinfoil models - we're working with other providers to be able to do this for more models and providers.
How to use it from the API
Private Mode is also available for API clients, but not by sending normal readable JSON directly to https://nano-gpt.com/api/v1/chat/completions.
For API use, run the NanoGPT Private Mode local proxy:
NANOGPT_API_KEY=sk-your-key npx @nanogpt/private-mode
Then point any OpenAI-compatible client at:
http://127.0.0.1:8787/v1
Example:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "http://127.0.0.1:8787/v1",
apiKey: "unused",
});
const response = await client.chat.completions.create({
model: "private/kimi-k2-6",
messages: [{ role: "user", content: "Hello" }],
stream: true,
});
You can list currently supported private models with:
curl http://127.0.0.1:8787/v1/models
The local proxy verifies the TEE attestation path, encrypts the request body on your machine, forwards the encrypted request through NanoGPT, decrypts the encrypted response locally, and returns a normal OpenAI-compatible response to your app.
That means API clients, CLIs, agents, and other OpenAI-compatible tools can use Private Mode without NanoGPT receiving the prompt or completion body as readable JSON.
How to verify in the browser
The first verification step is simple and does not require any special tools.
Before sending a request, click the Private Mode info icon in the model selector. It shows:
- the TEE target
- what NanoGPT can still see
- what NanoGPT should not be able to read
- a reminder to inspect the network request yourself
Then open your browser developer tools and inspect the private chat request in the Network tab. Your prompt should not appear as readable JSON in the request body.
This is not the full cryptographic verification story, but it is a useful sanity check: if your prompt is visible as ordinary JSON, you are not looking at the Private Mode encrypted request path.
Verification receipts
After a Private Mode response, the assistant message includes a shield icon. Click it to open the Private Mode receipt.
The receipt shows:
- whether the request was verified
- whether request and response encryption were active
- whether the response was streamed or non-streamed
- the TEE target
- the enclave host
- expected and runtime measurements
- attestation bundle hash when available
- receipt hash
- verifier step status
The verifier steps include:
| Step | Meaning |
|---|---|
| Release digest | The verifier found the expected release digest or policy evidence |
| Code provenance | The measured code matched the expected policy |
| TEE attestation | The enclave attestation checked out |
| Measurement match | The expected and runtime measurements matched |
| Certificate/key binding | The key material matched the verified environment |
The receipt does not include your prompt or the model's answer. It is intended to be safe to copy and share for verification.
Independent verification
The receipt popover has two copy buttons:
- Copy receipt JSON
- Copy verifier command
Save the receipt JSON as a file such as receipt.json, then run the verifier command shown in NanoGPT.
The intended command is:
npx @nanogpt/private-mode verify receipt.json
The verifier re-fetches fresh attestation evidence, runs the verifier locally, and compares the fresh result against the receipt.
It checks that:
- the receipt status is verified
- request and response encryption flags are true
- the NanoGPT proxy confirmation is present
- the expected measurement matches
- the runtime measurement matches
- the release digest matches
- the HPKE public key matches
An attestation bundle hash mismatch can be reported as a warning, because serialization can vary. Measurement, digest, or key mismatches are treated as failures.
What "verified" means
When a receipt says Verified, it means NanoGPT's browser-side Private Mode path saw a successful verifier result for the TEE target and confirmed that the private encrypted proxy path was used.
Why some features are blocked
Private Mode starts with the path we can explain clearly and verify defensibly.
That is why it currently blocks or turns off for cases like:
- attachments
- web search
- project tools and project context
- scraped URLs or scraped page content
- pending image descriptions
- multi-model chats
- prior non-text or tool messages
Those features can be useful, but they add extra content paths. If NanoGPT fetched a web page, processed an attachment, or assembled project context outside the encrypted TEE request body, it would be misleading to say the whole request was browser-private.
We would rather block those combinations than give a vague privacy claim.
Private Mode vs ordinary TEE models
Ordinary TEE routing can still improve security. It can reduce the trust surface around model execution and provide attestation for the environment.
Private Mode is stronger for prompt confidentiality because encryption starts in your browser before the request body reaches NanoGPT.
So the practical distinction is:
| Route | What improves |
|---|---|
| Ordinary hosted model | normal hosted inference |
| TEE model | stronger data-in-use and integrity story |
| Private Mode TEE model | TEE verification plus browser-encrypted request/response bodies |
Bottom line
Private Mode is our clearest privacy upgrade for hosted text models so far.
It is on by default for supported TEE models, easy to turn off, and designed to be inspectable rather than just trusted. You can check the request in browser network tools, inspect the receipt after the response, copy the receipt JSON, and verify the attestation evidence locally.
That is the standard we want for privacy features: not "trust us", but "here is what happened, here is what NanoGPT could see, and here is how to check it yourself."