Feature: Smart permission matching for compound shell commands

Resolved 💬 3 comments Opened Jan 26, 2026 by xEcEz Closed Jan 30, 2026

Description

Currently, Bash permission patterns use prefix matching against the entire command string. This means compound commands using &&, ||, |, or ; require explicit permission even when all individual commands are already allowed.

Current Behavior

With this configuration:

{
  "permissions": {
    "allow": [
      "Bash(cd:*)",
      "Bash(git:*)",
      "Bash(head:*)"
    ]
  }
}

This command still prompts for permission:

cd /home/user/project && git diff main...HEAD --name-only | head -30

The entire string is matched against cd:*, which technically matches, but the system doesn't recognize that all components (cd, git, head) are individually allowed.

Proposed Behavior

Parse compound commands and check each component against the permission rules:

  1. Split command on &&, ||, |, ; (respecting quotes and escapes)
  2. Extract the base command from each segment
  3. Allow if all segments match allowed patterns
  4. Deny if any segment matches a deny pattern

Example

cd /path && git status && npm install

Would be parsed as:

  • cd /path → matches Bash(cd:*)
  • git status → matches Bash(git:*)
  • npm install → matches Bash(npm:*)
  • Result: Allow without prompting
git status && rm -rf /

Would be parsed as:

  • git status → matches Bash(git:*)
  • rm -rf / → matches Bash(rm -rf /:*) in deny list ✗
  • Result: Deny

Motivation

  • Reduces permission fatigue for users with well-configured allow lists
  • Claude frequently chains commands for efficiency (mkdir -p && cd && git init)
  • Current workaround (Bash(*)) defeats the purpose of granular permissions

Implementation Considerations

  • Shell parsing is complex (subshells, command substitution, heredocs)
  • Could use a conservative approach: if parsing fails, fall back to current behavior
  • Could leverage existing shell parsers (bash's own parsing, or libraries like shlex)

Alternatives Considered

  1. Bash(*) with deny rules - Works but loses granular control
  2. Pre-command hooks - Possible but requires users to maintain external scripts
  3. Regex patterns - More powerful but harder to write correctly

View original on GitHub ↗

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