Guide
How can I stop an AI coding agent from running rm -rf or other destructive commands?
Updated
Short answer
A deny-list catches rm -rf as typed, but it misses the same delete written as find -delete, git clean or a script. What holds is a check at the agent's pre-execution hook, before the command runs, against what the session is supposed to be doing. Back it with scoped credentials and branch protection, not human approval: in Anthropic's study, testers caught the dangerous command 13.6% of the time.
Why a deny-list on rm -rf isn't enough
A deny rule matches text. Destruction is an effect, and text is only one way to write it.
`find build/ -delete`, `git clean -fdx`, a Python one-liner calling `shutil.rmtree`, a script the agent wrote ten steps ago, an alias, or `xargs rm` at the end of a pipe all do what `rm -rf` does. A rule for one spelling leaves the others open. A routine cleanup with a trailing `~/` is enough: Simon Willison wrote up a case where that expanded to the developer's home directory.
Deny-lists still earn their place. They're cheap, they stop the obvious cases, and Claude Code's permission rules support them. Treat them as the floor and build the real check on top.
The same command, two intents
Take `rm -rf ./build`. In a session cleaning up compiler output, that's fine. In a session where `./build` is a mounted volume holding someone's data, it's a disaster, and the text is identical.
So the check has to compare the pending action with what the session is doing. Where does the path actually resolve? Is the target inside the repo the task is about? Did the task ever mention deleting anything?
A list of forbidden strings can't answer any of those.
What each built-in control does and doesn't stop
- Permission rules. Fine-grained allow, ask and deny rules for what the agent can run. They match on the command pattern, so they inherit the spelling problem above.
- Sandboxes. Anthropic's sandboxing uses filesystem and network isolation, and Anthropic says effective sandboxing requires both. A sandbox caps the blast radius. It can't tell you whether a delete inside the allowed directory was intended.
- Hooks. A pre-execution hook sees the command before it runs, which is the right place to decide. What you put in the hook is the hard part.
- Scoped credentials. The strongest defense against database drops. If the agent's token can't delete the production database, the agent can't either.
Production databases and infrastructure
The destructive command isn't always a shell delete. It's `DROP TABLE`, a migration that rewrites a column, a `terraform destroy`, or an API call with an over-scoped token.
Treat these as their own class, with the same question: does this action match what the session was asked to do, in the environment it was asked to touch? A staging task that reaches for a production connection string should stop before the call goes out.
Pair that with credentials that can't do the damage in the first place, and backups the agent's token can't reach.
Force-push and pushing to main
GitHub blocks force pushes on protected branches by default, per its protected branches docs. Turn protection on for every repo that matters.
Know the catch: by default those restrictions don't apply to people with admin permissions. An agent running on an admin's token inherits that bypass unless you configure the rule to cover admins too.
Branch protection also only covers the branches you protect. A check at the hook covers the force-push to a feature branch a teammate was still using.
Why human approval doesn't hold
In Anthropic's controlled study, testers caught the dangerous command 13.6% of the time (143 of 1,053). Anthropic also reports that users accept 93% of manual prompts anyway.
An agent session averages about 145 actions, and long ones run past 1,000. Nobody reads that many prompts closely, so the approval click turns into a habit. Then the habit is your control.
A decision rule
- Deny the unambiguous cases outright: recursive delete at the root, force-push to the default branch, piping curl to a shell.
- Scope credentials so production deletes aren't possible from a laptop session.
- Protect branches, and apply the rules to admins.
- Check everything else at the pre-execution hook against session intent, not a string.
- Ask a human only for the genuinely ambiguous few, with the evidence attached.
- Start watch-only, read the log, then enforce.
Where Harden fits
Harden Agentic Integrity Foundation (AIF) runs on the developer laptop, outside the agent, at the agent's pre-execution hook. No command, file edit or push executes until Harden has checked it against the session's intent. Decisions are made locally, in milliseconds, and nothing leaves the machine.
Harden parses the command into a syntax tree and follows what it touches, so `find -delete` or a Python one-liner is judged by what it does, not how it's spelled. Destructive commands are checked against where they actually execute, so the same text inside a commit message doesn't trip a block. If the check can't run, the action doesn't run.
When Harden blocks, the agent gets the reason and can retry a safe way. In internal use, it made 0.25% wrong hard blocks over 24,809 decisions. It starts watch-only, and one policy covers every agent.
It's a layer, not a perimeter. It doesn't replace least privilege or scoped credentials. More detail: Security teams and AIF trust and security.
FAQ
Related questions
Does a sandbox stop rm -rf?
A sandbox limits where the agent can write, which caps the damage. It can't tell whether a delete inside the allowed directory was intended, so pair it with a check on the action itself.
Can I just block rm in the permission rules?
Block the clear cases, yes. But find -delete, git clean, scripts and language one-liners get the same result, so a pattern for one command leaves the others open.
How do I keep an agent from deleting a production database?
Give the agent credentials that can't delete production, keep backups its token can't reach, and check database and infrastructure commands against the session's task before they run.
Will a pre-execution check slow developers down?
Harden's verdicts take about 28 ms, with a P99 of about 70 ms, and wrong hard blocks ran at 0.25% over 24,809 decisions in internal use. It starts watch-only, so nothing gets blocked until you decide to enforce.
How do I stop force-pushes to main?
Turn on branch protection, which blocks force pushes by default, and configure the rule to cover admins too. Add a pre-execution check so the agent's push is judged before it leaves the laptop.