Deny rules should match subcommands in pipes and compound commands
Bug
Deny rules in permissions only pattern-match against the full command string, not against individual subcommands in piped or compound commands. This means a deny rule like Bash(rm *) is trivially bypassed:
Blocked (as expected)
rm -rf /foo
Not blocked (should be)
find /foo -type f | xargs rm
echo /foo | xargs rm -rf
cat files.txt | xargs rm
find /foo -exec rm {} \;
something && rm -rf /foo
something ; rm -rf /foo
Expected behavior
Deny rules should be evaluated against each segment of a piped/compound command, not just the full string. This is reportedly how allow rules already work — the docs state:
"Claude Code is aware of shell operators (like&&) so a prefix match rule likeBash(safe-cmd *)won't give it permission to run the commandsafe-cmd && other-cmd."
The same per-segment awareness should apply to deny rules. If rm appears as a subcommand in any segment of a pipe, &&, ||, or ; chain, and Bash(rm *) is in the deny list, it should be blocked.
Current workaround
Use broad wildcard patterns like Bash(* rm *) to catch rm anywhere in the command string. This works but is fragile and could false-positive on legitimate commands containing "rm" as a substring (e.g., grep "format" ...).
Environment
- Claude Code CLI
- macOS / zsh
settings.local.jsonpermissions config
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗