Permission matcher: Bash(rm .tmp/*) doesn't auto-approve matching commands
Bug: Bash(rm .tmp/*) allow rule doesn't match rm .tmp/<file> but Bash(rm -f .tmp/*) does
Environment
- Claude Code: latest (2026-04-12)
- Model: Opus 4.6 (1M context)
- OS: macOS Darwin 25.4.0 (aarch64)
- Shell: zsh, GNU coreutils rm 9.10 (also confirmed with
/bin/rm)
Reproduction
settings.json (both global and project-level):
{
"permissions": {
"allow": [
"Bash(rm .tmp/*)",
"Bash(rm -f .tmp/*)"
]
}
}
Test results:
| Command | Allow rule | Prompted? |
|---------|-----------|-----------|
| rm .tmp/test1.txt | Bash(rm .tmp/*) | Yes (bug) |
| rm -f .tmp/test2.txt | Bash(rm -f .tmp/*) | No (correct) |
| /bin/rm .tmp/file.md | Bash(rm .tmp/*) | Yes (bug) |
Expected behavior
rm .tmp/test1.txt should auto-approve — it matches the pattern Bash(rm .tmp/*).
Actual behavior
Only rm -f .tmp/* auto-approves. Bare rm .tmp/* always prompts despite having an identical allow rule (minus the -f flag).
Diagnostics ruled out
- No shell alias for
rm(type rm→ path to binary) - No deny rule matching
rm .tmp/* - No
settings.local.jsonoverride - No PreToolUse hook
- No entries in
/permissions"ask" list - File permissions: 644, umask 022
- Tested with both GNU coreutils rm and macOS
/bin/rm— same result
Hypothesis
The permission matcher may have special handling for bare rm <path> (no flags) that bypasses the allow list — possibly an implicit safety heuristic. The -f flag variant is not affected, suggesting the matcher treats rm + immediate path argument differently from rm + flag + path argument.
Workaround
Use rm -f .tmp/* instead of rm .tmp/*. The -f variant matches correctly.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗