Protecting Against Autonomous Agent rm -rf Commands
AI coding agents can run shell commands. Sometimes they run rm -rf by mistake. This deletes files forever. While of course I always read and approve all tool calls manually, by hand, and never let my agents work except under direct supervision 100% of the time, sometimes I miss things.
- Hooks catch
rm -rfbefore it runs - Refuse the command with a clear error telling you to use
trash - Lock the hook files so agents cannot delete them
Add to ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$HOME/.claude/hooks/deny-rm-rf.py"
}
]
}
]
}
}Create ~/.claude/hooks/deny-rm-rf.py:
#!/usr/bin/env python3
import json
import re
import sys
RM_RF_PATTERN = re.compile(
r"(^|[;&|]\s*)\s*(?:sudo\s+)?(?:command\s+)?rm\s+-(?:rf|fr)\b"
)
def main() -> int:
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as exc:
print(f"Error: Invalid JSON input: {exc}", file=sys.stderr)
return 1
if input_data.get("tool_name") != "Bash":
return 0
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")
if RM_RF_PATTERN.search(command):
print("Refusing to run `rm -rf`. Use `trash` instead.", file=sys.stderr)
return 2
return 0
if __name__ == "__main__":
sys.exit(main())Create ~/.config/opencode/plugin/deny-rm-rf.js:
const RM_RF_PATTERN = /(^|[;&|]\s*)\s*(?:sudo\s+)?(?:command\s+)?rm\s+-(?:rf|fr)\b/
export const DenyRmRf = async () => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool !== "bash") {
return
}
const command = output?.args?.command ?? ""
if (RM_RF_PATTERN.test(command)) {
throw new Error("Refusing to run `rm -rf`. Use `trash` instead.")
}
}
}
}An agent might try to delete the hooks. Make them immutable with macOS's chflags schg:
sudo chflags schg ~/.claude/hooks/deny-rm-rf.py
sudo chflags schg ~/.config/opencode/plugin/deny-rm-rf.jsOnly root can remove the immutable flag. Agents cannot bypass this.
- macOS
- trash:
brew install trash - sudo access to lock files
- macOS only
- Only blocks
rm -rf
When an agent runs rm -rf /path, the hook blocks it and tells you to use trash instead. You can then run trash /path manually to send files to the Trash.
See the full code at nateberkopec/dotfiles.
I had a version where I just automatically rewrote it to trash, but my recent updates to use jq apparently are breaking it.
nateberkopec/dotfiles#123