[FEATURE] Permission system should evaluate piped commands independently, not as a single string
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
The current Bash permission pattern matching treats an entire pipeline as one string, meaning Bash(tee:*) doesn't match something | tee logfile because the command doesn't start with tee. This is both a UX problem (the "don't ask again" suggestion is wrong) and a conceptual one.
The core issue: piping is data routing, not execution risk. The risk surface is in what each individual command does. rg foo | tee out.txt is not more dangerous than rg foo — tee just redirects stdout to a file.
Related: #29967 documents the symptom; this is the underlying design issue.
Proposed Solution
each subcommand in a pipeline should be evaluated independently against the allowlist. Only prompt if any individual subcommand isn't covered. This matches the actual threat model (which commands run, not how their output is connected).
Alternative Solutions
n/a
Priority
Low - Nice to have
Feature Category
Interactive mode (TUI)
Use Case Example
n/a
Additional Context
_No response_
8 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
I'd like to extend this request beyond pipes to all shell operators:
&&,;, and||.My use case:
I have
Bash(git *)in my global allow list. When Claude Code runs a singlegitcommand, it's auto-allowed as expected. But when it chains commands like:```bash
git stash pop && git add docker/dynamodb/files.json && git commit --amend --no-edit
I get a permission prompt — even though all three sub-commands individually match Bash(git *).
This happens frequently because Claude Code itself generates chained commands for good reasons:
The current behavior creates a frustrating gap: the permission system correctly blocks chains containing unauthorized commands (good), but doesn't allow chains where every sub-command is already authorized.
Proposed behavior:
Split on shell operators (&&, ;, ||, |), check each sub-command against the permission rules independently, and auto-allow the full chain only if every part matches. This would unify the handling for both pipes and logical operators.
This is essentially the inverse of the fix in #270 — that issue ensured users are prompted for all commands in a chain, this one asks that the allow rules be evaluated with the same granularity.
Still seeing this on v2.1.79. Both
cargoandtailare in my globalsettings.jsonallow list, butcargo clippy --all-targets --all-features -- -D warnings 2>&1 | tail -30still prompts for approval. Runningcargo clippywithout the pipe goes through fine.The fix claimed in #1271 (v1.0.110) doesn't appear to have fully resolved this.
/tmp/gh-comment-body.txt
Hooks already evaluate piped commands independently:
Each component (
ls,grep,sort,wc) is evaluated independently. If all are in your allow list, the entire compound command is auto-approved. No "single string" evaluation bug.Another real-world example hitting this on v2.1.81, Windows 11 (Git Bash):
Both
Bash(az:*)andBash(python:*)are in globalsettings.json, yet the compound command prompts for approval every time.This pattern (CLI tool producing JSON piped to python/jq for formatting) is extremely common in Azure/cloud workflows. Having to approve it manually on every invocation significantly slows down development.
+1 for evaluating each subcommand in a pipeline independently.
Thanks for the report. This is a duplicate of #29967 — consolidating tracking there.
This is how permissions already work: Claude Code splits Bash commands on shell operators (
|,|&,&&,||,;,&, newlines) and checks each piece against your rules on its own. Sorg foo | tee out.txtis allowed when bothBash(rg *)andBash(tee *)are covered, and choosing "don't ask again" saves a separate rule for each piece that needed approval rather than the whole pipeline string.Docs: https://code.claude.com/docs/en/permissions#compound-commands
If you're seeing a specific pipeline still prompt with matching rules for every segment, that would be a bug; please open a new issue with the exact command and rules. Closing this one as already available.
🤖 Generated with Claude Code