Deny rules are bypassable via flag reordering (e.g. git -C) — need finer pattern matching
The bug
Permission patterns use prefix matching. Deny rules are trivially bypassed by reordering flags.
Bash(git reset --hard:*) blocks git reset --hard but not git -C /path reset --hard. Same command. The -C flag just changes the working directory.
Broadening with Bash(git -C:*) breaks deny rules: git -C /path add -A sails through because Bash(git add -A:*) doesn't match commands starting with git -C.
The documented * syntax that would allow mid-pattern wildcards doesn't work in settings.json (#24815). The :* syntax that does work only supports prefix matching.
Steps to reproduce
- Add
Bash(git reset --hard:*)to deny rules insettings.json - Have Claude execute
git -C /some/path reset --hard - The command runs without being denied
The feature request
The pattern system needs finer granularity. Right now there is no way to express "deny this subcommand regardless of flags." Some options:
- Support mid-command wildcards (the
*syntax that's documented but broken) - Regex support in patterns
- Semantic matching that understands command structure (e.g. git subcommand extraction)
Related issues
- #24815 —
*syntax doesn't work insettings.json - #21642 — Official commit plugin missing required git commands in
allowed-tools - #14956 — Skill
allowed-toolsdoesn't grant Bash permission
Workaround
I wrote a PreToolUse hook in Go that parses the actual command string, strips global flags, and enforces deny/ask rules on the normalized subcommand. Writeup and source: https://adriangalilea.com/claude-code-permission-bypass
Environment
- Claude Code 2.1.38
- macOS
- Anthropic API
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗