[BUG] Bash permission pattern breaks when command contains parentheses
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Any ( or ) character in a Bash command causes the permission allow-list matching to fail, even when the command should match a Bash(... **) pattern.
What Should Happen?
Parentheses in command strings should be treated as literal characters during permission matching. For example, with "Bash(cat **)" in the allow list, cat 'hello()' should be auto-allowed just like cat 'hello' is.
Error Messages/Logs
Steps to Reproduce
- Add "Bash(cat **)" to the permissions.allow list in .claude/settings.json:
{
"permissions": {
"allow": [
"Bash(cat **)"
]
}
}
- Test various commands:
| Command | Expected | Actual |
|------------------|--------------|--------------|
| cat 'hello' | Auto-allowed | Auto-allowed |
| cat 'bla () bla' | Auto-allowed | Auto-allowed |
| cat 'hello()' | Auto-allowed | Prompts |
| cat 'bla(x)' | Auto-allowed | Prompts |
| cat 'bla)' | Auto-allowed | Prompts |
| cat 'bla(' | Auto-allowed | Prompts |
| cat '(bla' | Auto-allowed | Prompts |
| cat ')bla' | Auto-allowed | Prompts |
| cat 'bla(bla' | Auto-allowed | Prompts |
| cat 'hello() ' | Auto-allowed | Auto-allowed |
- Any ( or ) in the command breaks matching — except when surrounded by spaces (e.g. bla () bla).
- Workaround: Append a trailing space to commands that contain parentheses:
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.72 (Claude Code)
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Xterm
Additional Information
_No response_
7 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
I think it may be a duplicate not sure, but this ticket is more basic and contains more cases
Facing similar here for Next.js projects, closed my own issue https://github.com/anthropics/claude-code/issues/33827 to consolidate.
Hitting this as well on macOS. My specific case:
Allow rule:
Bash(ls:*)in.claude/settings.local.jsonCommand that prompts despite the rule:
The path contains Expo Router's
(app)directory convention, which uses literal parentheses in the directory name. The shell-escaped\(app\)breaks the permission matcher.Over time my settings have accumulated a bunch of overly-specific one-off entries like:
…because the general
ls:*glob never matches these.This is a common pattern in React Native / Expo projects where route groups use
(group-name)directories, so it affects anyone working in those codebases.Environment: Claude Code on macOS, latest version
Thanks for the report and the trailing-space workaround. This is fixed in v2.1.89.
Root cause in v2.1.72: the redirect-stripping step parsed and re-serialized the command, which dropped single quotes —
cat 'hello()'becamecat hello(). The now-unquoted()then tripped the compound-command guard, which refused to match prefix/wildcard allow rules. Your trailing-space workaround happened to bypass the broken re-serialize step.In v2.1.89 the redirect stripper preserves quoting, and all 7 cases from this issue return
allowwithBash(cat:*). Please upgrade and reopen if you still see it.Seems to work well now, thanks!
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.