Problem
The official bash_command_validator_example.py in the claude-code repo documents the exit code protocol:
- Exit 0 = allow, no message to Claude
- Exit 1 = show stderr to user only (not Claude)
- Exit 2 = block the tool call, show stderr to Claude
validate-bash-commands.py exits 0 and prints to stdout — so Claude may or may not see the warnings, and the tool is never blocked. The official example uses exit 2 with file=sys.stderr to actually block bad commands.
Source
claude-code/examples/hooks/bash_command_validator_example.py and claude-code/plugins/security-guidance/hooks/security_reminder_hook.py
Fix
validate-bash-commands.py: use sys.exit(2) with print(..., file=sys.stderr) for warnings that should reach Claude and block execution
- Review all hooks for correct exit code usage
Problem
The official
bash_command_validator_example.pyin the claude-code repo documents the exit code protocol:validate-bash-commands.pyexits 0 and prints to stdout — so Claude may or may not see the warnings, and the tool is never blocked. The official example uses exit 2 withfile=sys.stderrto actually block bad commands.Source
claude-code/examples/hooks/bash_command_validator_example.pyandclaude-code/plugins/security-guidance/hooks/security_reminder_hook.pyFix
validate-bash-commands.py: usesys.exit(2)withprint(..., file=sys.stderr)for warnings that should reach Claude and block execution