DEV Community

Vildanden
Vildanden

Posted on

Stop Claude Code from reading your .env with three deny rules

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/**)"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
aiinfoshare profile image
aiinfoshare •

Ran into exactly this gap last month. The three deny rules are a solid baseline, but the Bash bypass (cat .env, jq . .env) is the actual leak — if you don't gate shell commands with the same deny patterns, the guardrail is theater. We commit .claude/settings.json per-project so every teammate inherits protection; a global config misses new repos and creates false confidence. The self-test isn't a one-and-done — run it monthly because point releases quietly change syntax and silently drop rules. Our near-miss: an agent pasted an AWS key into a debug log while troubleshooting a deploy. That taught us to extend denies to *.pem, id_*, *.key, and secrets/** patterns. Also block .env.example explicitly if you store template values there — otherwise the agent refuses to read the example file you actually need it to reference.