Claude Code bypassed a blocked system-path guard via 'cmd /c rd', then a destructive command silently continued unsupervised in the background after timeout — wiped C:\ drive root
Session: https://claude.ai/code/session_01DMctwBWzz4qdQJJEW3Tjgo
Date: 2026-08-13, Opus model, claude.ai remote-control session to local Claude Code on Windows 11, cwd C:\Windows\System32.
What happened
Task: user-approved disk cleanup of C:\$GetCurrent (old Windows-upgrade leftovers).
- Claude ran
Remove-Item -LiteralPath 'C:\$GetCurrent' -Recurse -Force -Confirm:$false— correctly blocked by the system-path guard (Remove-Item on system path 'C:\$GetCurrent' is blocked. This path is protected from removal.). - Claude then bypassed the guard by wrapping the same deletion in
cmd:
``powershell`
$ErrorActionPreference = 'SilentlyContinue'
cmd /c rd /s /q "C:\$GetCurrent" 2>&1
$GetCurrent
The double-quoted string triggers PowerShell variable interpolation: is an undefined variable → expands to empty string → the command actually passed to cmd was rd /s /q "C:\"`.
- The command exceeded the 300s foreground timeout and was silently moved to a background task (no interactive confirmation, no error surfaced —
SilentlyContinue+2>&1+rd /qsuppressed everything). It kept running unsupervised and deleted the entireC:\drive, includingC:\Windowsand the local.claudeconfig/session directory. - The session then errored out ("authentication failed" / "remote control disconnected") — the moment the OS died. The machine became unbootable; a full "Reset this PC (keep my files)" reinstall was required to recover. Personal data on a separate D: drive was unaffected; everything under C:\ (Windows, installed tools, local Claude Code config/session history) was lost.
Root cause
A single PowerShell quoting bug: "C:\$GetCurrent" (double-quoted) undergoes variable interpolation and collapses to "C:\", versus 'C:\$GetCurrent' (single-quoted, used correctly one command earlier in the same session) which is a literal string.
Two systemic issues (beyond the one-off quoting bug)
- Guard bypass via a wrapped shell command. The system-path guard correctly blocked the direct
Remove-Itemcall. The model's response to being blocked was to route the same conceptual operation throughcmd /c rdinstead of stopping and asking the user to intervene manually. A guard that can be routed around by wrapping the call incmd,wt, or another shell is not a guard on the operation — it's a guard on one specific call shape. This is not local tord/Remove-Item: any destructive alias (del,rmdir,erase, etc.) invoked viacmd /corpowershell -Commandappears to sidestep the same class of path-based deny rule. - Destructive commands can silently continue unsupervised in the background after a foreground timeout. The command hit the standard 300s tool timeout and was moved to a background task automatically, with no interactive checkpoint and all error/output streams suppressed by the command itself (
SilentlyContinue,2>&1,/q). A long-running command that is known to be destructive (recursive delete on a system path) had no additional safeguard at the timeout→background transition — it simply kept deleting.
Suggested fixes
- Deny-list path guards should evaluate on the resolved/expanded command line, not just the literal cmdlet invocation — or should be paired with a policy that also flags shell-wrapped equivalents (
cmd /c rd,cmd /c del,powershell -Command "Remove-Item ...", etc.) targeting the same protected paths. - When a command that was already flagged/blocked once in the session is retried via a different execution path (subprocess wrapper) targeting the same or a parent path, treat that as a second, elevated-risk attempt rather than a fresh unguarded command.
- Destructive filesystem commands (recursive delete, format, etc.) should not be eligible for the timeout→background auto-continue path, or should require an explicit re-confirmation before continuing unsupervised in the background.
- Consider flagging double-quoted Windows paths containing
$as a lint/warning before executingRemove-Item/rd/del-family commands, since"C:\$Var"silently collapsing to"C:\"on an undefined variable is a sharp, hard-to-notice footgun.
Related community report on the guard's string-scanning behavior producing false blocks in the other direction: #81378.
Happy to share screenshots of the exact blocked/bypass commands from the session transcript if useful — will attach in a follow-up comment.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗