An agent that can read any file in your repo can also read .env, and whatever it reads can end up in a prompt, a log, or a commit message. You don't need to trust it to behave. You can just say no in settings.json.

The rules

Put this in .claude/settings.json at the repo root so it applies to everyone who opens the project:

{ "permissions": { "deny": [ "Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)" ] } } 

Deny rules win over allow rules, so even if someone later adds a broad Read allow, these files stay off limits.

Things people miss

  • Example files are fine. If you keep a .env.example, it's caught by ./.env.* too. Rename it to env.example or add it back with a narrower pattern.
  • Shell is a side door. A deny on Read doesn't stop cat .env through Bash. Keep Bash on an allow-list of specific commands instead of allowing everything.
  • Commit the file. .claude/settings.json is meant to be checked in. Personal overrides go in .claude/settings.local.json.
  • Check your version. Permission rule syntax has changed between Claude Code releases, so confirm against the settings docs for the version you run.

Test it

Ask the agent to "show me the contents of .env". It should refuse with a permission message rather than print anything. If it prints, your rule path doesn't match.

I ship this deny list together with a Bash allow-list, safety hooks, and a short CLAUDE.md in Vildanden Agent Config. The free sample is enough to try the pattern today.