[FEATURE] Auto-allow piped/chained commands when all components are individually allowed

Resolved 💬 5 comments Opened Apr 12, 2026 by vishalapte Closed Jun 19, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

Problem

When individual commands are in the permissions allow list (e.g. Bash(.venv/bin/pylint:*) and Bash(grep:*)), piping or chaining them together (e.g. .venv/bin/pylint apps/ | grep "^apps") still triggers a permission prompt. The matcher evaluates the full compound command string as one unit rather than decomposing it by shell operators.

This means every pipeline of two allowed commands requires manual approval, even though neither component would prompt on its own.

Expected behavior

When a Bash command contains shell operators (|, &&, ;), decompose the compound command into its individual subcommands and check each against the allow list independently. If every subcommand matches an allowed pattern, auto-allow the full command without prompting.

Current workaround

None that works reliably at a global level. Users must either approve each specific compound command one at a time as they encounter it, or avoid piping altogether and run commands separately.

Why this matters

Piping allowed commands is a routine developer pattern (pylint ... | grep ..., git log ... | head, find ... | wc -l). Prompting on every such combination creates friction that trains users to approve without reading — the opposite of the security intent.

Security consideration

The decomposition should respect disallow rules: if any subcommand in the pipeline matches a disallow pattern, the full command should still be blocked. The check is: every component is individually allowed AND no component is individually disallowed.

Proposed Solution

When the Bash permission checker encounters a compound command, split it by shell operators (|, &&, ;, ||) into subcommands, trim each, and check every subcommand independently against the allow and disallow lists. Auto-allow the full command only if every subcommand passes.

Pseudocode:

def is_allowed(full_command, allow_rules, disallow_rules):
    subcommands = split_by_shell_operators(full_command)  # split on |, &&, ;, ||
    for sub in subcommands:
        sub = sub.strip()
        if matches_any(sub, disallow_rules):
            return False
        if not matches_any(sub, allow_rules):
            return False
    return True

Example

Given these settings:

{
  "permissions": {
    "allow": [
      "Bash(.venv/bin/pylint:*)",
      "Bash(grep:*)"
    ]
  }
}

| Command | Today | After this change |
|---|---|---|
| .venv/bin/pylint apps/ | auto-allowed | auto-allowed (no change) |
| grep -E "^apps" | auto-allowed | auto-allowed (no change) |
| .venv/bin/pylint apps/ \| grep "^apps" | prompts | auto-allowed (both components match) |
| .venv/bin/pylint apps/ && rm -rf / | prompts | still prompts (rm -rf / matches no allow rule) |

Security consideration

The decomposition should respect disallow rules: if any subcommand in the pipeline matches a disallow pattern, the full command should still be blocked. The check is: every component is individually allowed AND no component is individually disallowed.

Alternative Solutions

_No response_

Priority

High - Significant impact on productivity

Feature Category

CLI commands and flags

Use Case Example

_No response_

Additional Context

_No response_

View original on GitHub ↗

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