How to stop Claude Code from reading your .env file
Add Read(./.env) and Read(./.env.*) to the permissions.deny array in .claude/settings.json. Deny rules are checked before allow rules, so the read is blocked even if something broader is allowed. Also deny Edit and Write on .claude/** so the agent can't remove the rule.
Stats from the 2026-10-20 snapshot of public GitHub configs (methodology). Behavior checked against the official docs linked below.
The rules
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(~/.aws/**)",
"Edit(./.claude/**)",
"Write(./.claude/**)"
]
}
}Read rules don't cover the shell
A Read deny stops the Read tool. It doesn't stop a Bash command like cat .env if you've allowed broad shell access. Avoid wildcard rules such as Bash(cat *) or Bash(python3 *), or add matching Bash denies. For stronger isolation, run Claude Code in a sandbox or container that doesn't have the secrets mounted.
Where to put it
Use .claude/settings.json if the whole team should get the rule (commit it). Use ~/.claude/settings.json to apply it to every project on your machine.
How many configs do this
Of 4,831 unique public Claude Code configs with a permissions block, 339 (7%) deny reading .env files. Even among the 694 configs that have any deny rule, only 48.8% cover .env.
FAQ
Does .gitignore stop Claude Code from reading .env?
No. .gitignore controls what git tracks. Claude Code can still read an ignored file unless a deny rule blocks it.
Should I deny .env.example too?
Read(./.env.*) also matches .env.example. That's usually fine. If you want the agent to see the example file, add an explicit deny for each real env file instead (.env.local, .env.production).