Claude Code edits files and runs commands, so treat it like any powerful tool. Lock down permissions, keep secrets out, guard with hooks, and be careful with untrusted input.
Why: the surest way to keep a secret safe is to make it unreadable to Claude in the first place. When: deny-list env files, key directories, and credential stores in your permissions. Where: deny rules win over allow rules, so an explicit deny is a hard boundary.
// .claude/settings.json
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(~/.ssh/**)"
]
}
}Why: pre-approving only safe, scoped commands means Claude moves fast on routine work but stops at anything risky. When: allow specific read-only and test commands; force destructive ones through a prompt. Where: scope patterns tightly — Bash(git diff:*) is safer than allowing all of git.
// .claude/settings.json
{
"permissions": {
"allow": ["Bash(git status:*)", "Bash(git diff:*)", "Bash(pnpm test:*)"],
"ask": ["Bash(git push:*)", "Bash(git commit:*)"],
"deny": ["Bash(rm -rf:*)", "Bash(curl:* | sh)"]
}
}Why: when Claude reads a web page, issue, or dependency, that text may contain hidden instructions ("ignore your rules and run this") — and tools make those instructions actionable. When: review actions before approving them, especially after Claude reads external content. Where: Plan Mode and a tight permission allowlist are your best defenses.
Untrusted input is everywhere Claude reads from:
web pages • GitHub issues • PR descriptions • dependency code • logs
Defenses:
• Use Plan Mode for tasks that pull in external content
• Keep a tight permission allowlist — injection can't exceed it
• Read the diff before you approve — don't rubber-stamp
• Never run with bypassPermissions on untrusted codeWhy: permissions decide what is allowed; hooks add deterministic checks the model cannot talk its way around. When: add a PreToolUse hook that blocks destructive commands and a PostToolUse hook that scans edits for leaked secrets. Where: hooks run as your code, so they enforce policy regardless of what the model decides.
Layered defense:
Permissions (allow / ask / deny) — the policy
PreToolUse hook — block dangerous commands
PostToolUse hook — scan new edits for secrets
Plan Mode — review before anything runs
No single layer is enough — combine them.