Compound-command detector flags read-only `cd && <cmd>` patterns, blocking common workflows
Compound-command detector flags read-only cd && <cmd> patterns, blocking common workflows
Summary
The built-in compound-command heuristic prompts for manual approval on any Bash call containing cd plus another command with output redirection, regardless of whether the second command is read-only. This makes everyday patterns like cd <repo> && git grep ... 2>/dev/null | head un-runnable without human-in-the-loop approval — even when every individual command in the chain is on the managed-settings allow list.
The check appears to fire before permissions.allow is consulted and before PreToolUse hooks run, so neither admins nor users can carve out exceptions for safe shapes.
Reproduction
In a project with /etc/claude-code/managed-settings.json containing:
{
"permissions": {
"allow": [
"Bash(cd *)",
"Bash(git *)",
"Bash(grep *)",
"Bash(head *)"
]
}
}
Ask Claude to do something that produces this command:
cd /home/me/repo && git grep -n "viewport" website/src/ 2>/dev/null | head -20
Actual: A permission prompt appears with the message:
Compound command contains cd with output redirection - manual approval required to prevent path resolution bypass
Expected: The command runs without prompting, since every component (cd, git, grep, head) is on the allow list and none can write to the filesystem or escape the user's permissions.
Why this matters
The intent of the check (prevent something like cd /etc && rm -rf * 2>/dev/null from quietly destroying things) is reasonable, but the heuristic is too broad:
- It treats all redirection as suspicious, including
2>/dev/nullwhich is purely cosmetic noise suppression. - It treats all "second commands" as suspicious, including read-only ones (
git grep,git log,ls,cat,head,find, etc.). - It bypasses the configured allow list, so admins who have explicitly allowed
Bash(cd *)andBash(git *)can't communicate "these compositions are also fine."
The practical effect for us: the agent learns to avoid cd && git ... and uses git -C <path> ... instead, which works for git but doesn't generalize. For tools without an equivalent -C flag, the agent is forced to either (a) split into two Bash calls (extra round trips) or (b) trip the prompt and break flow.
We had previously addressed this with an agentkit PreToolUse hook that decomposed compound commands and approved each piece individually. The built-in detector now adjudicates before hooks run, so that mitigation no longer works.
Suggestions
Listed in rough order of preference:
- Make the detector configurable. Add a managed-settings field like
permissions.compoundCommandPolicywith valuesstrict(today's behavior),relaxed(only flagcd+ write/network commands likerm,mv,curl,wget,dd), ordisabled. - Honor the allow list as an exception path. If every individual command in a compound (separated by
&&,|,;,||, newlines) matches an allow-list pattern, skip the prompt. - Run hooks before the built-in detector, or at least give hooks a way to mark a command as already-validated. This restores admin/user control without weakening the default for unconfigured users.
- Narrow the heuristic to write-capable second commands. A read-only second command (no shell redirection to a file, no
rm/mv/>etc.) doesn't enable the "path resolution bypass" the message warns about —cd /etc && cat passwdis no more dangerous thancat /etc/passwd.
Environment
- Claude Code version: 2.1.161
- Platform: Linux (Ubuntu)
- Managed settings: present at
/etc/claude-code/managed-settings.json - Reproduces in
acceptEditspermission mode.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗