What
Claude Code checks shell commands before running them. The part that looks at rm and rmdir (the commands that delete files and folders) now catches more risky shapes. It already had a narrower check for paths built on a possibly empty variable. Commands it catches are refused with an explanation and need your explicit approval. Permission rules (your saved allow lists) cannot approve them automatically.
- A target that starts with a shell expansion the check cannot read, such as
$PREFIX, and ends in a top-level directory name like bin, etc, usr, var, Users, Windows, System or cygdrive. The message explains that if the expansion is empty, the command removes/<name>. - A target made only of backslashes, which Git Bash on Windows treats as the drive root.
- Variable tracking across the whole command: assignments, variables built from other variables,
unset,forloops, heredocs (blocks of inline text fed to a command), and values from$(pwd),$(dirname …),cdorgit rev-parse. A variable counts as possibly empty when it is not in the environment or is set to an empty string.TMPDIRis treated as set when sandboxing (Claude Code's restricted mode for running commands) is on. - An rm whose path could expand to
/or a folder directly under it now needs approval. This also applies when a command is too complex to parse or analyse, so the empty-variable check now runs in those cases too.
The new checks sit behind a server-controlled switch, tengu_bright_lake. Its built-in fallback is on, and it is turned off only when a server setting explicitly sets it to false.
Why
A command like rm -rf "$PREFIX/usr" or rm -rf "$DIR/"* with an unset variable can delete a system directory or everything under the root. These shapes are now stopped before they run, and no saved permission rule can wave them through.