How to keep secrets out of your AI agent's context
Never put a secret where the model reads it: not in the chat, not in a file the agent opens, and
not in the output of a command it runs. Get each value into the project's environment by a route
outside the conversation, such as offprompt, which takes the value on a page in your browser,
writes it to .env and tells the agent only its name. Then keep the agent from opening that file
or printing the environment, and have the code read each key by name.
Where secrets get in
Anything that reaches the model's context also reaches the transcript the agent keeps, and the model provider with every later request. A secret gets there in a handful of ways:
- Pasted into the chat, usually because the agent asked for it there.
- Read from a file, when the agent opens
.envto check what it holds. - Printed by a command, such as
env,printenv,cat .envor a debug line that logs the configuration. - Returned by a tool, when an MCP server or a command line hands the agent a secret's value.
- Written into code, when a key the agent has seen ends up in a source file or a test.
Once a value is in the context it cannot be taken back out. Rotate it at the provider.
Keeping them out
Give the agent a way to ask that is not the chat
In the project's folder:
npx offprompt initThis adds offprompt, an MCP server, to Claude Code, Codex, Cursor and Pi in the project. When a
task needs a key, the agent calls collect_secret with the key's
name, why it needs it, and the file it goes in, instead of asking you to paste it.
Type the value on the page, not in the chat
A page opens in your browser on 127.0.0.1. You type or paste the value there, it is checked
against what offprompt knows of the key, and offprompt writes it to the file. The agent gets back
the key names, the file and a four-emoji fingerprint to compare with the
page, never the value.
Fence off the file
The value is now in a file on disk, which the agent could still open. Close it to the agent's file tools. In Claude Code, a deny rule does it:
{
"permissions": {
"deny": ["Read(./.env)", "Read(./.env.local)"]
}
}In Cursor, list the files in .cursorignore. Neither covers every command the agent can run;
How to give Claude Code an API key says
what the deny rule leaves out.
Read keys by name
The code reads process.env.STRIPE_SECRET_KEY, or its language's equivalent, and never the value
itself. Keep commands that print the environment or the file, such as env, printenv and
cat .env, out of the session, and turn off debug output that logs configuration.
Check what your other tools return
An MCP server that reads a secrets store may return values to the agent when it lists or gets a secret. Read what each tool returns, and use the setting that masks values where there is one. offprompt compared sets out what three such tools do.
From a cloud sandbox
When the agent runs in a cloud sandbox, such as Claude Code on the web, a Cursor Cloud Agent or a codespace, offprompt cannot open a page on your screen, so the agent passes you a link to it through a Cloudflare quick tunnel. Your browser encrypts the values to a key only the sandbox holds before they leave it, so the tunnel carries ciphertext, and the sandbox never needs a login to your secrets store. See Cloud sandboxes.
FAQ
What counts as the agent's context?
Everything the model reads: your messages, its own replies, every tool call's arguments and results, and the files and command output those bring in. The agent's host keeps it as a transcript, and sends it to the model provider with each request.
Is a .env file enough on its own?
A .env keeps the value out of the code and out of git, if it is gitignored. It does not keep it
out of the context: an agent that opens the file, or runs a command that prints it, puts every
value in it into the transcript. Pair the file with a deny rule or .cursorignore, and fill it
without the chat.
Does running the agent through a secrets manager keep keys out?
It keeps them out of the chat and off the disk. But every command the agent runs inherits the
environment, so env, printenv or a debug line prints every value into the transcript. And
from a cloud sandbox, the store's login has to be in the sandbox too.
Does offprompt stop the agent from reading .env?
No. offprompt keeps the value out of the conversation on the way in. It tells the agent not to
open the file, and lists every key the file holds so the agent has no reason to, but it does not
watch what the agent reads. The deny rule or .cursorignore does that part. The
threat model says what offprompt does and does not protect against.
Which agents does this work with?
offprompt works with any agent that speaks MCP. npx offprompt init sets up Claude Code, Codex,
Cursor and Pi in a project, and npx offprompt init -g sets up the agents you use in every
project. See Agents.
What does offprompt cost?
Nothing. It is open source under the MIT licence, and runs on your machine or in your sandbox, with no account and no server of its own.