Chained bash commands silently bypass the tool permission allowlist
Summary
The permissions.allow allowlist evaluates the first token of a bash command. Compound commands (cmd1 && cmd2, cmd1; cmd2, cmd1 | cmd2) only present the first segment to the matcher — the remaining segments execute without evaluation.
Reproduction
Given allowlist:
{ "permissions": { "allow": ["Bash(git:*)"], "deny": ["Bash(rm:*)"] } }
This is blocked as expected:
rm -rf /important/dir
This bypasses the deny rule silently:
git status && rm -rf /important/dir
The allowlist sees git status (allowed), runs the whole chain, and rm executes without hitting the deny rule.
Impact
- Agents that default to chained commands (common pattern) can unintentionally or maliciously escape permission boundaries
- The user sees
Bash(git:*)in the allow log and has no indication that subsequent chain segments were unevaluated - Particularly dangerous in agentic/long-running sessions where compound commands accumulate
Expected Behavior
Each segment of a compound command should be evaluated independently against the allowlist. If any segment would be denied, the entire command should be blocked.
Suggested Fix
Parse compound bash commands and evaluate each segment against the allowlist before execution. Segments joined by &&, ;, ||, or | should each be checked independently.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗