Bash permission glob matching breaks when command contains # character

Resolved 💬 7 comments Opened Mar 14, 2026 by nikicat Closed Apr 18, 2026

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?

The Bash permission glob matcher treats # as a comment delimiter even when it appears inside quoted arguments. This causes commands that match an allow rule to still trigger a permission prompt if any argument contains #.

Minimal Reproduction

  1. Add this allow rule to ~/.claude/settings.json:

``json
{
"permissions": {
"allow": [
"Bash(agent-slack search *)"
]
}
}
``

  1. Run a command without # — auto-allowed, no prompt:

``
agent-slack search messages "test" --channel "fee-strategies" --limit 1
``

  1. Run the identical command with # in a quoted argument — triggers permission prompt:

``
agent-slack search messages "test" --channel "#fee-strategies" --limit 1
``

The only difference between the two commands is "fee-strategies" vs "#fee-strategies". The first auto-allows; the second prompts.

What Should Happen?

# inside quoted strings should be treated as a literal character, not a comment delimiter. Both commands above match Bash(agent-slack search *) and should auto-allow.

Evidence from Session Logs

Analyzed two independent sessions (~180 JSONL lines total). Both show the exact same pattern:

| Phase | Commands | # in args | Permission prompted? |
|-------|----------|-------------|---------------------|
| Session 1, cmds 1–7 | agent-slack search/user/channel | No | No (auto-allowed) |
| Session 1, cmds 8–11 | agent-slack search ... --channel "#channel-name" | Yes | Yes |
| Session 2, cmds 1–7 | agent-slack search/user/channel | No | No (auto-allowed) |
| Session 2, cmds 8–12 | agent-slack search ... --channel "#channel-name" | Yes | Yes |

The transition from auto-allow to prompting happens precisely when # appears in arguments — not based on invocation count, parallelism, or subagent usage.

Likely Cause

The permission matcher appears to strip everything from # onward (treating it as a shell comment) before matching against the glob pattern, so the effective command becomes truncated and no longer matches.

Related Issues

  • #31889 — wildcard permission matching not working (TFS paths with spaces — possibly different root cause)
  • #29529 — Bash(curl *) not matching (could be partially explained by # in URL fragments)

Claude Code Version

2.1.76

Platform

Anthropic API

Operating System

Linux (Arch, 6.19.6-zen1-1-zen)

Terminal/Shell

fish

View original on GitHub ↗

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