Skip to content
All writing

How to Stop Claude Code from Reading .env Files

Stop Claude Code from reading .env files with a registered PreToolUse hook. Block common secret-file reads and keep API keys out of AI context.

#snippetsdev-toolssecurityai

To stop Claude Code from reading .env files, register a PreToolUse hook that denies matching file paths and environment dumps. The script below catches common secret-file access; keep production credentials outside the agent's reach too.

Save the script as ~/.claude/hooks/guard-env.sh. Run mkdir -p ~/.claude/hooks first, then chmod +x ~/.claude/hooks/guard-env.sh after saving.

#!/usr/bin/env bash
# PreToolUse hook (Read/Bash/Grep): blocks tool calls touching secret/credential
# files or dumping the environment.
#
# .env-style names are checked per token, so an allowlisted name elsewhere in
# the payload can't be smuggled in to defeat the guard (e.g. `cat .env .env.example`).

PAYLOAD=$(cat)

block() {
  printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"SECURITY: Blocked %s. Read .env.example or a schema file (env.ts/env.mjs) instead."}}\n' "$1"
  exit 0
}

# Secret paths and env dumps: any match blocks. 
DENIED='\.dev\.vars|\.pem\b|\.p12\b|\.pfx\b|\.ppk\b|\.p8\b|\bid_rsa\b|\bid_dsa\b|\bid_ed25519\b|\bid_ecdsa\b|\.ssh/|\.gnupg/|\.aws/|\.kube/config|\.docker/config|\.config/gh/|\.htpasswd\b|\.tfstate\b|\.[a-z0-9]+_history\b|(~|'"$HOME"')/\.(netrc|npmrc|pypirc|yarnrc|git-credentials|pgpass|my\.cnf|cargo/credentials|config/git/credentials|codex/config\.toml)|/proc/[^[:space:]]*/environ|\bprintenv\b|(^|[[:space:];&|"])env[[:space:]]*($|[";|&])'
printf '%s' "$PAYLOAD" | grep -Eiq "$DENIED" && block "a secret file or env dump"

KEYFILE='["'"'"'][A-Za-z0-9._~/-]*(\.key|credentials\.(json|ya?ml|toml)|secrets\.(json|ya?ml|toml))["'"'"']|(/|\./|~/)[^[:space:]"'"'"'{}()$]*(\.key|credentials\.(json|ya?ml|toml)|secrets\.(json|ya?ml|toml))\b'
printf '%s' "$PAYLOAD" | grep -Eiq "$KEYFILE" && block "a key/credential file"

while IFS= read -r tok; do
  case "${tok##*/}" in
    .env.example|.env.template|.env.sample|.env.defaults|env.ts|env.mjs|env.d.ts) ;;
    .env|.env.*|.envrc) block "a .env file" ;;
  esac
done < <(printf '%s' "$PAYLOAD" | grep -Eio '[^[:space:]"'"'"';|&<>()]*\.env[A-Za-z0-9._-]*')

exit 0

Merge this entry into hooks.PreToolUse in ~/.claude/settings.json. Preserve existing settings and hooks.

{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/guard-env.sh"
          }
        ]
      }
    ]
  }
}

Confirm the hook is loaded with /hooks. Test a dummy .env read and a permitted .env.example read before using it with a real workspace. See the Claude hook reference.

For other tools and the shared approach, read how to keep sensitive files and secrets out of AI coding agents.

Get new posts by email

New writing in your inbox. Unsubscribe anytime.