Bash permission matcher fails on compound shell constructs (pipes, subshells, heredocs)
Description
Bash commands that start with patterns present in the allow list in settings.json still trigger permission prompts when the command contains compound shell constructs.
Reproduction
Given this settings.json allow list (abbreviated):
"allow": [
"Bash(echo *)",
"Bash(cat *)",
"Bash(tail *)",
"Bash(jq *)"
]
The following commands all prompt for permission despite starting with allowed patterns:
- Subshell expansions:
```
echo '{"ts":"'$(date -Iseconds)'","slug":"foo"}' >> /tmp/test.jsonl
Bash(echo *)` — prompts.
Should match
- Piped chains with semicolons:
```
cat /path/to/file.jsonl 2>/dev/null | tail -5; echo "---"; hostname -s
Bash(cat *)` — prompts.
Should match
- Heredoc syntax:
```
cat >> /path/to/file.jsonl << 'EOF'
{"key": "value"}
EOF
Bash(cat *)` — prompts.
Should match
- Variable-assignment prefixes:
```
TS=$(date -Iseconds) && cat >> /tmp/log.jsonl << EOF
{"ts": "$TS"}
EOF
cat` which is allowed.
Starts with a variable assignment so no pattern matches, but the actual command being run is
Expected behavior
If Bash(echo *) is in the allow list, any Bash command starting with echo followed by any arguments should auto-allow, regardless of shell metacharacters in the arguments.
Actual behavior
Commands prompt for confirmation even though they match the glob pattern.
Environment
- Claude Code on macOS (Darwin 25.3.0)
- Permission mode: Ask (not dangerous/bypass)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗