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 0Merge 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.