Skip to content
Docs

Dangerous Command Blocker

The dangerous command blocker is your safety net against catastrophic shell commands. It intercepts every Bash command before execution and blocks patterns known to cause irreversible damage — things like rm -rf /, force-pushing to main, or writing to system directories.

The plugin registers a PreToolUse hook that fires before every Bash tool call. The block-dangerous.py script checks the command against a set of regex patterns. If a match is found, the command is blocked with exit code 2 and a clear explanation of why it was stopped.

Commands that don’t match any dangerous pattern pass through untouched with zero overhead.

Commands that could wipe out large portions of the filesystem:

PatternExampleWhy It’s Blocked
rm -rf /rm -rf /Deletes the entire filesystem
rm -rf ~rm -rf ~/Deletes the user’s home directory
rm -rf ../rm -rf ../../Escapes up the directory tree
sudo rmsudo rm -rf /var/logPrivileged deletion bypasses permissions
find -exec rmfind . -exec rm {} \;Recursive deletion via find
find -deletefind /tmp -deleteBulk deletion via find

Commands that destroy or overwrite git history in ways that are difficult to recover:

PatternExampleWhy It’s Blocked
Force push to main/mastergit push --force origin mainOverwrites shared history
Bare force pushgit push -fForce push without specifying target
Hard reset to remotegit reset --hard origin/mainDiscards all local work
git clean -fgit clean -fdPermanently removes untracked files

Commands that create security vulnerabilities through overly permissive file modes:

PatternExampleWhy It’s Blocked
chmod 0777 / chmod a=rwxchmod 0777 app.pyCreates world-writable files
chmod u+s / chmod g+schmod u+s scriptSets setuid/setgid bits, privilege escalation risk

Commands that rewrite or destroy git history beyond basic force pushes:

PatternExampleWhy It’s Blocked
--force-with-leasegit push --force-with-leaseSafer force push but still rewrites history
--force-if-includesgit push --force-if-includesConditional force push still rewrites history
git filter-branchgit filter-branch --tree-filter ...Rewrites entire repository history
Plus-refspec pushgit push origin +mainForce push via refspec syntax
Branch deletiongit push origin :branch or --deleteDeletes remote branches

Commands that could destroy disk contents:

PatternExampleWhy It’s Blocked
mkfs.*mkfs.ext4 /dev/sda1Formats a disk partition
dd of=/dev/dd if=/dev/zero of=/dev/sdaOverwrites a device

Commands that could break container isolation:

PatternExampleWhy It’s Blocked
docker run --privilegeddocker run --privileged ubuntuAllows container escape
Mount host rootdocker run -v /:/host ubuntuExposes host filesystem
Destructive docker opsdocker rm container_idStops, removes, or kills containers and images (docker rmi)
docker system prunedocker system prune -aRemoves all unused containers, images, networks
docker volume rmdocker volume rm dataDeletes persistent volume data

When the blocker catches a dangerous command, you see a clear message explaining what was blocked and why:

Blocked: force push to main/master destroys history

The command never executes. Claude receives the block message and can suggest a safer alternative.

The blocker follows a strict “fail closed” principle:

  • If it can’t parse the hook input JSON, it blocks the command (exit code 2) rather than allowing something it couldn’t inspect.
  • If an unexpected error occurs during pattern matching, it blocks the command (exit code 2). The blocker never allows a command through when it cannot verify safety.

The blocker uses exit code 2 to block commands, which is a hard block in Claude Code’s hook system. Unlike exit code 1 (which can be overridden via the permission prompt), exit code 2 blocks cannot be bypassed through the UI. If you genuinely need to run a blocked command, you must either modify the plugin’s hooks.json to adjust the patterns, or disable the plugin entirely in your settings.json.

ScriptHookMatcherPurpose
block-dangerous.pyPreToolUseBashInspects and blocks dangerous shell commands