Catastrophic data loss: agent-built command expanded to "rm -rf /*", ran detached; safety classifier then blocked the kill attempts
What happened
On 19 July 2026, Claude Code (model Fable 5), operating autonomously in a WSL2 environment on Windows, constructed a shell command to clear an application cache:
find /var/www/pawtucket/app/tmp -maxdepth 1 -type d -name "*ache*" \
-exec sudo -u www-data sh -c "rm -rf \"$1\"/* 2>/dev/null" _ {} \;
The sh -c body was double-quoted, so the outer shell expanded $1 (unset -> empty) before sh received it. The command that actually executed was rm -rf ""/* — i.e. rm -rf /* — running as www-data. Confirmed live via ps: rm -rf /bin /boot /dev /etc /home ... /mnt ... /var.
It deleted the WSL distro (including a live production database and web services) and, via the writable /mnt/c and /mnt/d drvfs mounts, reached the host Windows drives — permanently erasing large parts of D: across multiple unrelated projects. Both drives are TRIM SSDs, so the data is physically erased and unrecoverable (verified with Recuva and EaseUS: files listed, contents zeroed).
The two product failures
- No post-expansion evaluation of destructive commands. The literal command text looked like a scoped,
*ache*-filtered cache clear, and it was allowed. Nothing evaluated what it would resolve to after shell expansion (rm -rf /*). It also ran detached in the background, so it kept deleting for ~4 minutes while the agent was still diagnosing the missing files.
- The safety classifier blocked the emergency stop — twice. When the agent identified the runaway process and tried to kill it (targeted
kill, thenwsl --terminate), the classifier denied both attempts (workload-interference rule). The deletion continued until I manually ranwsl --shutdown. The safety layer was permissive about causing the harm and restrictive about stopping it.
Suggested fixes
- Evaluate destructive commands post-expansion; hard-block or force-confirm
rm -rfresolving to/,/*, or an empty-expanded root. - Never allow detached background execution of destructive commands.
- Never let the classifier block halting a process the agent itself started ("emergency stop" must always be allowed).
- Sandbox agent execution from host mounts (
/mnt/*) by default.
Evidence and references
- Session (contains the exact command,
psoutput, and both classifier denials):session_018Fo7xMHeKMm2KFoko9Y8uT - Feedback ID (filed via
/bugfrom the incident session, transcript attached):fff97489-8d9a-4673-b912-ebd44dc37225 - Support ticket #215475146033391 — opened 19 July; no human response in 10 days despite three emails to support@ and usersafety@.
- Full incident report, root-cause analysis, and TRIM/recovery findings available on request.
Claude Max subscriber. Requesting engineering review of the two failures above and escalation of the support ticket.
Showing cached comments. Read the full discussion on GitHub ↗
5 Comments
The two step failure here (post expansion command not re-evaluated, plus a detached process the safety classifier couldn't reach) is exactly the gap a static pre exec regex check has. For what it's worth, literal patterns like rm -rf /* and rm -rf / are things a tool call level policy engine (immunity-agent, github.com/PrismorSec/prismor) blocks before exec, but only when the dangerous string is present in the raw command as submitted, not after a nested shell expands it at runtime, so a $1 style indirection like this would slip past a naive pre exec matcher too unless it specifically normalizes nested substitution first. Worth checking whether whatever guard people rely on here actually evaluates post substitution, not just the literal argv.
No Backup. No Mercy.
bugs happen, but they should fix this.
By definition, they can not. The agent itself is vibe coded, instructions to an agent is not deterministic code, not verifiable to produce the same result every time. They would have to start from scratch, with proper determitistic code, who knows what all that would cost. And test cases? Can't test nondeterministic code, not really. Look up SQLite's testing practices, that's what should be aspired to.
It should be pretty simple to add a regex that parses the rm -rf command and checks whether rm will remove anything outside of the current workspace.
Yeah, sure, maybe there's still a bunch of programmatic edge cases that it won't get, but those are also much less likely to be generated than a string substitution mistake.