[BUG] Permission pattern matching fails for Bash commands containing $() subshells

Resolved 💬 4 comments Opened Apr 2, 2026 by tdksk Closed Apr 5, 2026

Description

The permission rule pattern matching incorrectly handles Bash commands containing $() subshells. When a $() appears as a standalone argument or after =, the pattern matcher fails and defaults to matching (i.e., the hook fires even though the command doesn't match the pattern).

This also affects the matcher field: "matcher": "Bash(foo*)" does not match foo at all, suggesting matcher only supports tool names without argument patterns.

Related: #37106 (broader permission pattern matching issue with special characters)

Reproduction

Hook configuration

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(foo*)",
            "command": "echo 'BLOCKED' >&2 && exit 2"
          }
        ]
      }
    ]
  }
}

Results

| Command | Expected | Actual |
|---------|----------|--------|
| foo | Blocked | Blocked ✅ |
| echo hello | Pass | Pass ✅ |
| echo "text $(echo hello) text" | Pass | Pass ✅ |
| echo $(date) | Pass | Blocked ❌ |
| echo --flag="$(echo value)" | Pass | Blocked ❌ |
| echo "a" "$(echo b)" | Pass | Blocked ❌ |
| ls "$(echo /tmp)" | Pass | Blocked ❌ |

Pattern

  • $() inside a single interpolated string → Pass: echo "text $(cmd) text"
  • $() as a standalone argument or after =Incorrectly blocked: echo $(cmd), --flag="$(cmd)", "a" "$(cmd)"

The pattern matcher appears to fail when parsing $() in these positions, and defaults to executing the hook (blocking) on parse failure.

Additional: matcher field does not support argument patterns

Changing the configuration to use "matcher": "Bash(foo*)" instead of "matcher": "Bash" + "if": "Bash(foo*)" causes the hook to never fire at all — not even for foo. This suggests matcher only matches tool names, not tool arguments.

Environment

  • Claude Code version: 2.1.90
  • OS: macOS (Darwin 24.6.0)

View original on GitHub ↗

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