[BUG] Bash deny pattern bypass via ${VAR} curly-brace variable expansion
Bash deny pattern bypass via ${VAR} syntax
Summary
Bash deny patterns using glob matching (e.g., Bash(*__phi*)) fail to match when the command string contains ${VAR} (curly-brace variable expansion). The literal substring is present in the command but the pattern matcher does not match it, causing the command to fall through to user prompt instead of being auto-denied.
Environment
- Claude Code on WSL2 (Linux 6.6.x)
- Sandbox enabled,
autoAllowBashIfSandboxed: false managed-settings.jsonwith deny patterns
Reproduction
- Add this to
managed-settings.jsondeny list:
``json``
"Bash(*__phi*)"
- Test commands:
````
ls $HOME/__phi/ → Auto-denied (correct)
ls ~/__phi/ → Auto-denied (correct)
echo __phi → Auto-denied (correct)
ls ${HOME}/__phi/ → Falls through to user prompt (BUG)
- The string
__phiis literally present inls ${HOME}/__phi/, yetBash(*__phi*)does not match.
Expected behavior
Bash(*__phi*) should auto-deny any command containing the substring __phi, regardless of surrounding syntax like ${...}.
Actual behavior
Commands containing ${VAR} appear to break the glob pattern matcher, preventing substring matches from working. The command falls through to the user approval prompt instead of being auto-denied.
Security impact
This bypasses deny patterns intended to protect sensitive directories. If a user clicks "approve" (e.g., not recognizing the path), the sandbox filesystem (read.denyOnly) does not provide a second layer of defense for Bash commands — only the Read/Glob/Grep tools are blocked by read.denyOnly.
Combined, this means:
- Deny pattern fails to auto-deny due to
${} - User approves (or has permissive settings)
- Sandbox filesystem does not block the Bash read
- Sensitive data is exposed
Related issues
- #23314 — Deny patterns don't match commands with heredoc syntax
- #18613 — Deny rules bypassed by flag reordering/insertion
All three issues point to the same underlying problem: the glob pattern matcher is too literal and can be bypassed by syntactic variations of the same command.
Suggested fix
The pattern matcher should either:
- Normalize/escape
${...}before matching, or - Use a matching algorithm that treats
{and}as literal characters in the command string being tested against deny patterns
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗