Ask a coding agent why your Stripe checkout fails and there's a good chance its first move is to open .env. It's the reasonable thing to do: the config is there. But now your live key is in the conversation, in the agent's logs, and on someone else's servers.
Here are the options I found for stopping that, from the simplest to the one I ended up building.
1. Tell the agent not to read it
Claude Code has permission rules in .claude/settings.json:
{
"permissions": {
"deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"]
}
}
Cursor has .cursorignore, which keeps files out of indexing and, on a best-effort basis, out of the agent's reach.
This is worth doing today, and it costs nothing. The gaps:
-
Rules match paths, not contents. A
config.local.jswith a pasted key isn't covered. -
The shell is a side door.
cat .env,grep KEY .env,python -c "print(open('.env').read())"orenvcan still show the values unless you deny those too. - You have to remember it in every project, and for every agent you use.
2. Don't keep the secrets in files at all
If there's no .env on disk, there's nothing to read. Tools like 1Password's op run, Doppler or Infisical inject variables into the process:
op run --env-file=.env.tpl -- npm run dev
The app gets the values in its environment; the repository only has references. This also helps with the classic "committed .env" accident.
The catch with agents: if the agent can run op read or printenv itself, it can still pull the value into the chat. Injection is necessary but not enough.
3. Check every request before the agent runs it
Both Claude Code and Cursor now have hooks that run before a tool call and can allow it, deny it or ask you:
- Claude Code: a
PreToolUsehook getstool_nameandtool_input(the file forRead, the command forBash) and answers withpermissionDecision: "deny"and a reason the model sees. - Cursor:
beforeReadFileandbeforeShellExecution.
A hook can do what static rules can't: look at the command (cat, grep, curl -d @.env, sh -c "…"), and look at the contents of the file the agent wants to read. The reason it returns matters too: if it says "use npm run dev with the variables injected instead", the agent usually adapts instead of retrying.
What I built
I wanted all three at once, so I built Safe8bit, a secrets vault for the Mac. The part relevant here is the Shield, a hook for Claude Code and Cursor that:
- denies reading
.envfiles, private keys and credential files (.netrc,~/.aws/credentials, SSH keys…), whether throughReador throughcat/grep/python/curl @file; - denies reading any file whose contents match a value stored in the vault, and writing those values into code;
- asks you before
printenv,env,export -por pulling a value out of the vault, including when they're wrapped insh -corsafe8bit run --; - tells the agent to run the app with
safe8bit run -- npm run dev, which injects the variables after Touch ID. Touch ID asks you, so the agent can start the app but never sees the keys.
Here's what that looks like in Claude Code when the agent reaches for the file:
● Read(.env)
└ Safe8bit: .env (.env file) isn't read by agents. Use environment variables
with safe8bit run (e.g. safe8bit run -- npm run dev) instead of reading the value.
The vault itself is one file encrypted with AES-256-GCM, with the key derived with Argon2id and protected by the Secure Enclave. No account, no server.
Its limits
A hook is a guardrail against accidents, not a sandbox. Code the agent runs inside safe8bit run can read its own environment (node -e 'console.log(process.env)'), and a determined agent could write a script that reads a file in a way no rule anticipates. What it fixes is the common case: an agent that reads your config because that's the obvious next step.
Try it
Whatever tool you use, do step 1 today. If you're on a Mac and want the rest, Safe8bit's free tier includes the vault and the Shield in log-only mode, so you can see what your agent would have read:
brew install --cask safe8bit-app/tap/safe8bit
safe8bit shield install
More, including a 30-second demo: https://safe8bit.com/en/
How do you keep secrets away from your agents? I'd like to know what I'm missing.
Disclosure: I'm the developer of Safe8bit. This article was drafted with AI assistance and reviewed by me.
Top comments (0)