Permission matcher: Bash(rm .tmp/*) doesn't auto-approve matching commands

Resolved 💬 4 comments Opened Apr 12, 2026 by arechste Closed May 23, 2026

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.json override
  • 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.

View original on GitHub ↗

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