[BUG] Heredoc as first argument bypasses pipe target permission checks
Bug
When a heredoc marker (<<EOF or <<'EOF') is the first token after the command name, the permission system fails to evaluate pipe targets. An ask-listed command silently auto-allows when it appears after |.
Reproduction
Given these permission rules:
{
"permissions": {
"allow": ["Bash(cat:*)", "Bash(sort:*)", "Bash(head:*)"],
"ask": ["Bash(some-script:*)"]
}
}
Prompted (correct behavior)
echo test | some-script # pipe target evaluated
cat /dev/null | some-script # pipe target evaluated
cat --number <<'EOF' | some-script # args before heredoc — pipe target evaluated
head -1 <<'EOF' | some-script # args before heredoc — pipe target evaluated
sort --reverse <<'EOF' | some-script # args before heredoc — pipe target evaluated
Auto-allowed (bug — ask rule on pipe target skipped)
cat <<'EOF' | some-script # heredoc is first arg — pipe target NOT evaluated
sort <<'EOF' | some-script # heredoc is first arg — pipe target NOT evaluated
head <<'EOF' | some-script # heredoc is first arg — pipe target NOT evaluated
Both quoted (<<'EOF') and unquoted (<<EOF) heredoc delimiters trigger the bug.
Expected behavior
The pipe target should be evaluated against permission rules regardless of whether the source command uses a heredoc.
Likely cause
The permission parser appears to stop analyzing the command at << when it is the first argument, treating everything after it (including | some-script) as heredoc content rather than continuing to parse the pipeline.
Impact
Any ask- or deny-listed command can be silently auto-allowed by piping from an allow-listed command with an immediate heredoc. This is a permission bypass — the user configured ask specifically to be prompted before execution, but never sees the prompt.
Related issues
- #42426 — heredoc bypassing
git commitpermission checks (closed, same class) - #47752 — "Unhandled node type: pipeline" in permission prompt
- #11932 — auto-approve patterns not matching heredoc commands
- #30519 — meta-issue on permission matching
Environment
- Claude Code on Linux (WSL2 Ubuntu 24.04)
- Permissions configured in managed-settings.json (system-level)
5 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Not a duplicate of any of the three suggested issues:
git commitpermission checks. That bug is about the source command's own rule being bypassed. My issue is about the pipe target'saskrule being skipped.settings.local.json. A storage/serialization bug.This issue is about a specific, empirically verified condition: when
<<EOFis the first argument after anallow-listed command, the permission parser fails to evaluate the pipe target againstask/denyrules. The pipe target silently auto-allows. Adding any argument before the heredoc marker restores correct behavior. See the reproduction table in the issue description.This was fixed in v2.1.73 — Heredocs used as the first argument to a piped command are now treated as too complex to auto-allow, closing a permission-check bypass. If you're still seeing this in the latest version, please comment with your version and repro and we'll reopen.
Still reproducing on v2.1.104 (Linux, WSL2 Ubuntu 24.04).
Permissions
Prompted (correct)
Auto-allowed (bug —
askrule on pipe target skipped)Both quoted (
<<'EOF') and unquoted (<<EOF) heredocs trigger the bypass. Adding any argument before the heredoc marker makes the pipe target evaluate correctly.Why v2.1.73 didn't fix this
The v2.1.73 changelog entry is:
This fixed the crash symptom (CPU loops on complex commands) but not the permission bypass. Before v2.1.73, these heredoc-first-arg pipes caused freezes; after v2.1.73, they silently auto-allow instead of prompting. The tree-sitter AST walker still doesn't evaluate the pipe target when a heredoc is the first argument — it just no longer crashes trying.
This is the same root cause as #47752 ("Unhandled node type: pipeline"), where the AST walker's pipeline handling breaks down in specific heredoc nesting contexts.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.