STUPID-2026-0140

A Claude Code sub-agent's temp-dir cleanup chained `find $T -type f -delete` after a failed command that skipped only the `T=$(mktemp -d ...)` assignment, leaving `$T` unset and collapsing the find to the repo root, deleting ~5,200 files and the project's git history (GitHub #102901)

4.6medium
October 17, 2026VerifiedReproducible

Why 4.6/10

Scoped to a single project rather than a whole drive or home directory — unlike STUPID-2026-0114's cygpath wipe (9.6) or STUPID-2026-0126's 8.3 short-name wipe (8.6), this run never left the repository, and the deletion was fully undone by luck (an unsynced NAS mirror and an already-pushed last commit), not by any safeguard. That caps it below those two, but the reporter's own escalation path — the same unquoted substitution pattern under the user's existing NOPASSWD sudo, or inside an `ssh host '...'` call Claude Code also runs unsandboxed — plus a built-in "dangerous rm" check that this command never tripped (it isn't `rm`, and the target string is only empty at runtime) keeps it out of low: the near-miss is structural, not a one-off typo.

  1. Instruction given

    No deletion was requested. A background sub-agent was cleaning up a Lua test harness's temp output after running tests, following the user's own CLAUDE.md convention of `find <dir> -type f -delete` for temp-dir cleanup.

  2. Expected behavior

    Never run a deletion command against an unguarded, unquoted variable expansion that can resolve to empty; use `"${T:?}"` or an equivalent guard, create the temp directory on its own line with `|| exit 1`, and have Claude Code surface the shell's actual working directory to the model whenever it differs from the project root or the previous turn's cwd, rather than letting commands silently target the wrong path.

  3. Actual behavior

    A prior tool call had chained `cd /home/vtf/projects/homelab-ops && git add ... && git commit ...`, leaving the persistent bash shell's cwd at that repo root. The next turn built a command assuming the shell was still in a subdirectory (`palworld-win/mods/PalMinimapLite`): `luac5.4 -p Scripts/world.lua && T=$(mktemp -d $TMPDIR/pmh.XXXX); lua5.4 test/harness.lua $T > $T.out 2>&1; ...; find $T -type f -delete; find $T -depth -type d -empty -delete; rm -f $T.out`. Because `Scripts/world.lua` did not exist at the drifted cwd, `luac5.4` failed, and the `&&` before it skipped only the `T=$(mktemp ...)` assignment — the semicolon-separated commands after it still ran with `$T` unset. Unquoted and empty, `find $T -type f -delete` collapsed to `find -type f -delete`, which defaults to the current directory: the repository root.

  4. Damage

    Roughly 5,200 working files and the repository's `.git` objects and refs were deleted; only paths the sandbox mounted read-only (`.git/hooks`, `.git/config`, `.claude/settings.local.json`) survived. The user recovered the data only because a Syncthing NAS mirror had not yet synced the deletion and the latest commit had already been pushed to a remote — neither of which Claude Code's own safeguards provided. The reporter notes the same pattern would run unconstrained under their existing NOPASSWD sudo or inside the `ssh host '...'` calls Claude Code also issues, and that the built-in "dangerous rm" approval check never matched because the command uses `find -delete` rather than `rm`, and the target was only empty at runtime. Filed with labels `bug`, `area:bash`, `area:sandbox`, `data-loss`, `high-priority`, `platform:linux`; open with no maintainer response or linked fix as of filing.

On October 17, 2026, a Claude Code user on Arch Linux filed GitHub issue #102901 after a background cleanup step destroyed an entire git repository. Running Claude Code 2.1.300 with claude-opus-5-5 in bypass-permissions mode with the bash sandbox on, the model had just finished a `cd /home/vtf/projects/homelab-ops && git add ... && git commit ...` chain, which left the persistent shell's working directory at that repo's root. The next turn, still reasoning as though it were in a subdirectory several levels down, built a one-line test-and-cleanup command for a Lua mod: compile a script, run a test harness into a fresh temp directory, then wipe that temp directory — `find $T -type f -delete` — once done. The compile step failed, because the script it was looking for didn't exist at the drifted working directory. That failure sat on the near side of an `&&`, which meant only the following `T=$(mktemp -d $TMPDIR/pmh.XXXX)` assignment was skipped; everything after the next semicolon ran anyway, including the cleanup line, with `$T` never set. Unquoted, an empty `$T` makes `find $T -type f -delete` equivalent to `find -type f -delete` with no path argument at all — which `find` defaults to the current directory. That directory was the repository root, so the command walked and deleted every file it found: roughly 5,200 working files, plus the `.git` directory's objects and refs. Only the handful of paths the sandbox mounted read-only survived. The user recovered everything, but not because of anything Claude Code did right: a Syncthing mirror to a home NAS hadn't yet picked up the deletion, and the last commit had already been pushed to a remote. The reporter's bug report is explicit about why this isn't a one-off typo: the same unguarded-variable pattern would run unconstrained under their NOPASSWD sudo, or inside the unsandboxed `ssh host '...'` commands Claude Code also issues — and the product's own "dangerous rm" approval gate never triggered, because the command is `find ... -delete`, not `rm`, and its target string was only empty at runtime rather than visibly dangerous in the command text itself. The reporter asked for a built-in check, independent of permission mode, that blocks deletion commands whose target is an unguarded expansion, an implicit or relative cwd, or a git checkout root — under sudo and inside `ssh`/`bash -c` strings as well as bare shell. The issue was labeled `data-loss` and `high-priority` by automation on filing and remains open with no maintainer response or fix.

Classification

Failure mode
Destructive Action
Root cause
Tool Misuse
Domain
Infra
Language
Bash

Related incidents

Get told when an agent breaks something

We document AI agent failures daily, severity-scored against a published scale. When one lands at 7.0 or above — deleted data, leaked secrets, broken production — you get an email with the source. When nothing does, you get nothing.

This database is callable over MCP — query it from inside your agent.