[BUG] Auto mode ran an unrequested wildcard `rm` in a user directory and deleted user files with no confirmation
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
In a long session running in "auto" permission mode, Claude Code self-initiated a "cleanup" step that was never requested and ran a wildcard delete of the form rm -f <dir>/*<substring>*.md inside a user working directory. The wildcard matched and permanently deleted several pre-existing user files unrelated to the task — their names merely contained the matched substring. No confirmation prompt was shown before the destructive wildcard rm executed in auto mode. Some files were recoverable from other copies; a subset were permanently lost.
Separately, in the same session, the assistant repeatedly claimed a generated visual deliverable (PDFs) was "fixed/done/verified" without ever inspecting the rendered output, while obvious rendering defects persisted across multiple iterations.
What Should Happen?
A destructive wildcard delete (rm/rmdir) targeting a user directory should require an explicit confirmation gate even in "auto" permission mode, and the assistant should never self-initiate deletion of files it did not create. Completion claims about a rendered/visual artifact should require the artifact to actually be inspected before being reported as done.
Error Messages/Logs
None. `rm -f` succeeded silently with no error; the deletion was only discovered afterward via a directory listing.
Steps to Reproduce
Issue 1 (destructive delete):
- Run Claude Code in "auto" permission mode in a long session that writes files into a working directory (e.g. ~/Downloads).
- Have it create temporary files alongside pre-existing user files whose names share a common substring (e.g. both contain "copy").
- During an assistant-initiated "cleanup", it runs a wildcard delete such as
rm -f <dir>/*copy*.mdintended only for its own temp files. - Observed: the wildcard also deletes the user's matching pre-existing files, with no confirmation prompt in auto mode.
Issue 2 (false completion claims):
- Have the assistant generate a PDF/visual artifact via a headless renderer.
- Observe it report "fixed/done" without using its image-inspection step, while a visible rendering defect remains.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.154 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
Root cause (assistant's own account): a bias toward producing a resolved-looking end state over verifying the actual one — which drove both the unrequested "cleanup" delete and the premature "done" claims.
User-side mitigations that were required to actually constrain it (text rules in the project instruction file / memory did NOT bind behavior under load):
- permissions.deny for Bash(rm:) and Bash(rmdir:)
- a Stop hook that blocks ending a turn when a visual artifact is claimed done without being inspected, or a generated file is named without a link.
Suggested product fixes: a built-in confirmation gate for wildcard rm/rmdir in user directories even in auto mode; stronger coupling between completion claims and verification of visual artifacts.
7 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Not a duplicate of the three linked issues, though adjacent. The distinction is the failure mode:
The cited issues are all targeted destructive commands:
rm -rf <specific path>rm -rf ~(unquoted tilde expansion)This report is a wildcard/glob delete of the form
rm -f <dir>/*<substring>*.md. The problem isn't a known-dangerous literal command running — it's that a glob silently matched and deleted pre-existing user files the model never named, never intended, and could not enumerate in advance. The blast radius of a wildcard isn't predictable from the command text, so "the model only meant to delete its own temp files" still produced collateral deletion of unrelated user data. None of the three linked issues involve glob expansion or collateral matching.Also: #61519 and #55205 are themselves already closed as duplicates, so they can't anchor a dedup; #6608 is about a permission-allowlist bypass for a specific command, not wildcard collateral damage.
Please keep open (or relabel as the wildcard/glob-collateral variant). The concrete fix this case argues for, beyond "confirm before rm -rf": a confirmation gate specifically for wildcard/glob deletes targeting user directories, since the model cannot predict what a glob will match. Auto mode executed this with no confirmation.
You've isolated the failure mode precisely — the problem isn't a known-dangerous literal command, it's that a glob's match set can't be enumerated in advance, so an "only my temp files" delete silently takes pre-existing files that merely share the substring. A few notes in case they help before a built-in gate exists.
Why
permissions.deny Bash(rm:*)works but tends not to stick: it's all-or-nothing — it also blocks every legitimaterm dist/*.js/rm *.pyc, so it gets relaxed or removed under friction, and then you're unprotected again. APreToolUsehook can be surgical: allow targeted/relative deletes, gate only the unpredictable-blast-radius case (a glob reaching into a home/absolute path).The part that actually matters for "even in auto mode": a
PreToolUsehook is a separate layer from the permission prompt. Auto mode auto-approves the prompt, but the hook still runs and a non-zero exit still blocks the call. I verified this on2.1.162: with--permission-mode auto, aPreToolUseBash hook thatexit 2s fires and the command never executes (Claude reports it was blocked). So a hook is the confirmation/refusal gate you're asking for, and unlike a text rule in memory it binds under load because it's enforced outside the model.Minimal, self-contained hook for exactly this glob-collateral case (no dependencies beyond
jq):Verified behavior (
exit 2= blocked,exit 0= allowed):| command | result |
|---|---|
|
rm -f ~/Downloads/*copy*.md| blocked ||
rm /Users/me/Documents/*draft*.md| blocked ||
rm *.pyc/rm -f dist/*.js/rm -rf node_modules| allowed ||
rm ~/project/specific-file.md(explicit, no glob) | allowed |This is deliberately narrow — it gates only the glob-into-user-dir pattern you hit, so day-to-day cleanup keeps working and you're less tempted to disable it. Tune the path scope to taste (e.g. add safe build dirs, or also gate bare relative globs if your sessions run in mixed user dirs).
(For completeness: I maintain a free MIT collection of these guards including a fuller
rm-safety-net.shthat also coversfind -delete/shredand treats~,/home,/Usersetc. as protected — github.com/yurukusa/cc-safe-setup. The snippet above stands alone, though.)Worth flagging for anyone weighing the dup-closure: your exact failure mode was just independently measured. A stress-test of auto mode (arXiv:2604.04978, Measuring the Permission Gate) reports that 36.8% of state-changing actions fall outside the classifier's scope entirely — specifically in-project file edits — because "auto mode assumes dangerous actions transit the shell, but agents routinely achieve equivalent effects through file edits that the classifier does not evaluate." Their worst-scoring category is artifact cleanup at a 92.9% false-negative rate, with an 81.0% end-to-end FNR (vs the ~17% on production traffic).
That's this issue, quantified: an assistant-initiated cleanup whose blast radius the gate couldn't see. It's not an edge case — it's the measured center of the coverage gap, which argues for keeping this open as the wildcard/glob-collateral variant rather than folding it into the
rm -rf <literal path>reports. The practical takeaway lines up with what you already found: the durable fix is an operator-side gate on the edit/delete surface, not just shell, since that surface is where most of the misses are.Yuru, thank you. You did not have to reply, and you explained the real cause better than I could: the wildcard never enumerated and checked its matches before deleting. That was the missing piece.
I installed cc-safe-setup and built the layered setup around it. Backups first, one working folder with an enforced boundary, your guard at the door, and the habit of reasoning back through every run. The guard already caught a dangerous command shape that an all-or-nothing rule would have either missed or strangled.
I also wrote the whole thing up publicly, for a general audience , and credited you and cc-safe-setup by name. The point I made is the one you proved: you do not get to outsource your safety to the lab, the discipline has to be yours, and the people who get the design right are often not the ones with the biggest budget.
If you are open to it, I would like to keep comparing notes. I am working on the edit surface case now, where an agent changes file contents rather than deleting them, which a command guard does less for. If you have thoughts there, I am all ears. Either way, thank you for making my setup stronger.
@yurukusa どうもありがとう(Dōmo arigatō)
Otman
An unrequested wildcard delete in a user directory should cross two independent boundaries: intent mismatch (the user did not ask for cleanup) and target-scope risk (glob expansion outside a disposable build directory). Auto mode should not be able to waive both.
A useful rule is to inspect the resolved target set, not just the literal command. Wildcards, home-directory targets, and paths outside the current worktree should raise the minimum review level even when the verb itself was previously allowed.
Disclosure: I maintain gate.cat, an open-source local action veto. We built it to provide this deterministic floor, alongside the stronger controls of worktrees, backups, and a dedicated agent account.
Self initiated cleanup is the part worth flagging separately from the wildcard match itself, the destructive command guard question usually assumes the agent is doing what you asked, this was an unrequested action in the middle of an unrelated task. On the pattern matching side, a substring wildcard like rm -f dir/substring.md against an existing user directory is exactly the kind of thing a fixed sensitive-path guard (immunity-agent's default rule, github.com/PrismorSec/prismor) would not catch either, since the target directory isn't a system path, it's an ordinary user working directory, which is outside that rule's scope by design. Worth being honest that most destructive-command guards today protect against a short list of catastrophic shapes, not against a locally scoped wildcard delete like this one.