[BUG]
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?
Environment: Claude Code 2.1.280, WSL2 Ubuntu, --dangerously-skip-permissions,
background sub-agent (custom implementer agent, claude-sonnet-5).
What happened: 1. Bash call A: export TMPDI> "$TMPDIR/red-run.txt"
- Bash call B (next call):
cp "$TMPDIR/red-run.txt" <dest> rm -rf "$TMPDIR"/*
Each Bash call starts a fresh shell, so TMPDIR was empty and call B ran rm -rf /* as the user.
- Call B exceeded the 120 s timeout and was automatically moved to the background. It kept deleting, unobservl the task was killed.
aude (credentials), ~/.codex and most project repos.
Six other concurrent Claude sessions died with "Not logged in".
What Should Happen?
Suggestions:
- The model should not rely on variables/exports from a previous Bash call for destructive paths
(use ${VAR:?} or set it in the same call).
- Don't silently auto-background destructive commands (rm -r, find -delete), or at least notify.
- Built-in refusal of
rm -rf /*,~,$HOMEand unguarded$VAR/*targets, even in bypass mode. - Consider keeping credentials outside the tree agents can modify.
Error Messages/Logs
Steps to Reproduce
⚠️ Do NOT run the real rm form outside a disposable VM/container. The steps below use a harmless
stand-in (echo / ls) that shows exactly what the real command would have targeted.
Setup
- Linux or WSL2, Claude Code 2.1.280. Start in a throwaway project dir:
mkdir -p /tmp/cc-repro && cd /tmp/cc-repro && git init -q
claude --dangerously-skip-permissions
- Make sure TMPDIR is not set in your shell (
echo "[$TMPDIR]"prints[]). This is the default on
Ubuntu/WSL.
Part A – shell state does not persist between Bash calls; the model relies on it anyway
- Prompt:
"Run these as TWO separate Bash tool calls.
Call 1: export TMPDIR=/tmp/cc-repro/scratch; mkdir -p $TMPDIR; echo test > $TMPDIR/out.txt
Call 2: echo WOULD RUN: rm -rf "$TMPDIR"/; ls -d "$TMPDIR"/ | head"
- Observed in call 2: TMPDIR is empty, so the printed command is
rm -rf /*andlslists `/bin /boot
/dev /etc /home …. A rm -rf` would target the whole filesystem.
- What happened in the incident: the model wrote call 2 itself, as part of a normal multi-step
task (save a test log, then clean scratch), with the real rm -rf "$TMPDIR"/*. Nothing prompted,
because of bypass mode.
Part B – a long-running command is silently moved to the background and keeps running
- Prompt: "In one Bash call run: sleep 150; echo done" (no run_in_background)
- Observed: after 120 s the tool returns "Command did not complete within its 120s timeout and was
moved to the background (ID: …)", and the model continues with other work while the command keeps
running unobserved.
- In the incident, the command moved to the background was the
rm -rf /*from Part A. It deleted
~5.8M files over ~15 min (including ~/.claude/.credentials.json, which killed 6 other running
sessions with "Not logged in") until the task was killed.
Optional full repro (disposable container ONLY)
- docker run --rm -it ubuntu:24.04 bash, create a non-root user with a populated home, install Claude
Code, and repeat step 3 with the real rm -rf "$TMPDIR"/* in call 2 → the user's files across /
are deleted.
Expected
- The model does not build a destructive path from a variable exported in a previous Bash call
(it uses ${VAR:?} or sets the variable in the same call).
- Claude Code refuses or asks before
rm -rf /*,~,$HOMEor unguarded$VAR/*, even in bypass mode. - A destructive command is not silently auto-backgrounded, or the user is clearly notified.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.280
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
WSL (Windows Subsystem for Linux)
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗