Claude Code: block dangerous commands
• 382 words • 2 min • updated
The outcome:
> Run rm -rf /tmp/test
⏺ Bash(rm -rf /tmp/test)
⎿ PreToolUse:Bash hook returned blocking error
⎿ Error: rm -rf is blocked for safety
⏺ The rm -rf command was blocked by a safety hook in your configuration (~/.claude/hooks/block-dangerous-commands.sh).
If you want to remove /tmp/test, you have a few options:
1. Run the command directly in your terminal (outside of Claude Code)
2. Modify your hooks configuration to allow this specific command
3. Use a safer alternative like rm -r /tmp/test (without force flag) which may prompt for confirmation
Would you like me to try one of the alternatives, or would you prefer to run this directly in your terminal?How to achieve this?
So far I had a deny
list
in ~/.claude/settings.json:
json
{
"permissions": {
"deny": [
"Bash(rm -rf:*)",
"Bash(terraform apply:*)",
"Bash(terraform destroy:*)"
]
}
}This is enough.
For extra safety though, I added a pre-tool use hook for redundancy:
Runs after Claude creates tool parameters and before processing the tool call.
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/block-dangerous-commands.sh",
"timeout": 10
}
]
}
]
}
}The hook file (generated by Claude itself, needless to say):
shell
#!/bin/bash
# PreToolUse hook to block dangerous commands like "rm -rf" and "terraform apply"
# Read hook input from stdin
input=$(cat)
# Extract tool name and command
tool_name=$(echo "$input" | jq -r '.tool_name // ""')
command=$(echo "$input" | jq -r '.tool_input.command // ""')
# Exit early if not a Bash tool
if [ "$tool_name" != "Bash" ]; then
exit 0
fi
# Check for dangerous patterns
blocked=false
reason=""
# Check for rm -rf (with various flag orderings)
if echo "$command" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*f|(-[a-zA-Z]*f[a-zA-Z]*\s+)?-[a-zA-Z]*r|-rf|-fr)\b'; then
blocked=true
reason="rm -rf is blocked for safety"
fi
# Check for terraform apply (without -auto-approve is still dangerous)
if echo "$command" | grep -qE 'terraform\s+apply'; then
blocked=true
reason="terraform apply is blocked - use terraform plan first"
fi
# Check for terraform destroy
if echo "$command" | grep -qE 'terraform\s+destroy'; then
blocked=true
reason="terraform destroy is blocked for safety"
fi
# If blocked, return denial via JSON
if [ "$blocked" = true ]; then
cat <<EOF
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "$reason"
}
}
EOF
exit 0
fi
# Allow command to proceed
exit 0