PowerShell tool: destructive-path guard mis-extracts an unrelated quoted token as the delete target (false-positive blocks)

Open 💬 2 comments Opened Jun 18, 2026 by hiiqbiz-wq

Bug: PowerShell-tool destructive-path guard mis-extracts an unrelated quoted token as the delete target

Summary

Claude Code's built-in protected-path guard (the one that blocks destructive file ops on system/root paths with "Remove-Item on system path 'X' is blocked. This path is protected from removal.") does a crude static scan of the whole command for a path-like/quoted token near Remove-Item, and can grab a token from somewhere other than the actual delete target. When that wrong token happens to look root-like (e.g. a leading-slash string) or is just an unrelated quoted literal, the guard blocks a command that never targeted a protected path. The legitimate Remove-Item in these cases targeted an ordinary repo-relative file (e.g. .git/index.lock).

Environment

  • Claude Code on Windows 11, PowerShell tool (CLAUDE_CODE_USE_POWERSHELL_TOOL=1, pwsh 7).
  • Guard fires before execution; no user hook is involved (confirmed: the message string exists in no settings file, hook, or managed-settings path — it's the built-in).

Steps to reproduce / observed cases

Two real false-positives, both in compound (;-joined) commands whose only Remove-Item targeted a benign relative path:

  1. Commit message with a slash-token. A command that deleted .git/index.lock and then ran git commit whose message contained the substring /synthesize.
  • Expected: lock removed, commit made.
  • Actual: blocked — "Remove-Item on system path '/synthesize' is blocked. This path is protected from removal." The guard grabbed the commit-message text, not the Remove-Item argument.
  1. -split regex literal. A command of the shape Remove-Item <relative-path> ... ; ($line -split '\s+').
  • Expected: file removed, split runs.
  • Actual: blocked — "Remove-Item on system path '\s+' is blocked. This path is protected from removal." The guard grabbed the regex literal '\s+' as the "path."

A related, previously-noted variant: when the Remove-Item target is an unresolvable variable (e.g. Remove-Item $lock), the guard assumes / (root) and blocks.

Intermittency

The mis-extraction is inconsistent — minimal synthetic repros (e.g. Remove-Item .\nonexistent.txt -ErrorAction SilentlyContinue; $m = "add /synthesize route") did not trip it, while the real-world compound commands above did. So the trigger depends on command shape (likely the position/quoting of tokens relative to Remove-Item), not merely the presence of a slash-string. This makes it hard for users to predict or avoid.

Impact

  • Legitimate commits and cleanup commands are blocked, wasting tool calls and forcing awkward workarounds ([System.IO.File]::Delete('<literal>'), splitting commands, or falling back to Bash rm -f).
  • The guard cannot be disabled or scoped by the user, so there is no configuration-level mitigation — only command-rewriting.

Suggested fix

Parse the actual Remove-Item target rather than any quoted substring in the command:

  • Bind to the value of -Path / -LiteralPath, or the first positional argument of the Remove-Item invocation specifically.
  • Restrict protected-path matching to tokens that are genuine filesystem paths (drive-letter C:\…, UNC \\…, or resolvable repo-relative paths). Ignore regex/option strings, command-argument values of other commands in the pipeline (e.g. git commit -m …), and unrelated quoted text.
  • For unresolvable-variable targets, prefer "allow + warn" (or resolve the literal assignment when present) over assuming /.

Keep the genuine protection — Remove-Item C:\Windows\…, Remove-Item /, recursive-force on system roots should still block. The ask is only to stop blocking commands that merely mention a path-like or quoted string elsewhere.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗