[BUG] Reduce use of heredoc pattern

Resolved 💬 17 comments Opened Nov 4, 2025 by amiramir Closed Mar 14, 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

Of late CC seems to love heredoc for creating docs. It uses heredoc pattern to create a file in /tmp and then copies it over to my repo.

The problem is that each heredoc need an explicit approval. And then there is the copy. Any agentic feel is lost and I am turned into a watcher to hit carriage return to give permission for various CC tasks.

This is particularly bad with the explore agent which may user heredoc half a dozen times during and exploration so it's not really an agent in the fire and forget sense.

I have put a decent amount of instructions in various CLAUDE.md files to forbid the use of heredoc or to encourage the write tool to no avail.

Proposed Solution

This seems to be new behavior over the last week or so.
The solution would be to never user heredoc. There may be some niche edge cases for it but for creating a new document or some other thing in my repo where CC has full permissions seems unnecessary and wasteful.

Alternative Solutions

_No response_

Priority

High - Significant impact on productivity

Feature Category

Interactive mode (TUI)

Use Case Example

_No response_

Additional Context

_No response_

View original on GitHub ↗

17 Comments

mkokotovich · 8 months ago

I have also experienced this problem. I have tried adding Bash(cat:*), Bash(echo:*) to my permissions allow list, but it still asks me every time.

I would like to either be able to allow claude to proceed without asking each time, or for it to use this pattern less (or never).

cnighswonger · 8 months ago

This is a Bug, Not a Feature Request

We've spent several hours systematically debugging heredoc permissions and can confirm this is a bug in the permission matching system, not a missing feature.

What We Discovered

Pattern matching works for simple commands but fails for heredocs:

Working:

"Bash(python3:*)"

Correctly matches and auto-approves: python3 -c "print('hello')"

Not Working:

"Bash(python3:*)",
"Bash(python3 <<:*)",
"Bash(python3 << :*)",
"Bash(python3 << 'EOF':*)"

None of these patterns match: python3 << 'EOF'\ncode\nEOF

We tested multiple variations with different spacing, quoting, and wildcard placement. None work.

Evidence This is a Bug

  1. Prefix matching works for other commands:
  • "Bash(python3:*)" successfully matches python3 -c "..." and python3 script.py
  • According to IAM docs, prefix matching should match "any command starting with" the pattern
  1. Heredocs fail across all commands:
  • python3 << 'EOF' doesn't match "Bash(python3:*)"
  • cat << 'EOF' doesn't match "Bash(cat:*)"
  • Even git commit with heredoc patterns don't match general "Bash(git commit:*)" patterns
  1. Multi-line commands break prefix matching:
  • The approval dialog shows the full multi-line heredoc string
  • Pattern matching appears to fail when newlines are present in the command string

Technical Details

When a heredoc command is submitted, the approval prompt shows:

python3 << 'EOF'
print("example")
EOF

The permission pattern "Bash(python3 << :*)" should match this via prefix matching, but it doesn't. This suggests the pattern matcher either:

  • Doesn't handle newlines in command strings
  • Treats heredoc operators specially in a way that breaks prefix matching
  • Has a bug in how it tokenizes/compares multi-line bash commands

Workaround Attempted

Per the IAM docs, we tried the recommended allowlist approach with multiple pattern variations. None work for heredocs.

The only "workaround" is accepting exact-match permissions (generated when clicking "Allow for entire session"), which creates one permission entry per unique heredoc content. This is impractical for scripting workflows where heredoc content changes frequently.

Impact on Workflow

High severity for Python/scripting workflows:

  • Python inline scripts require constant manual approval
  • Each approval interrupts the agentic flow
  • Breaks iterative development (every script variation needs re-approval)
  • No practical pattern-based solution exists

Affects multiple tools:

  • Python heredocs (most common in our workflow)
  • Shell script generation (bash << 'EOF')
  • Configuration file creation via heredocs
  • Any multi-line command pattern

Expected Behavior

Pattern matching should work consistently:

  • If "Bash(python3:*)" matches python3 -c "code", it should also match python3 << 'EOF'\ncode\nEOF
  • Prefix matching should evaluate the command prefix before the heredoc operator
  • OR: Provide a specific wildcard for heredocs like "Bash(python3 <<**)" if multi-line matching needs special syntax

Request

This should be labeled as a bug and prioritized for the permission matching system. Heredocs are fundamental to shell scripting and Python inline workflows. The current behavior breaks documented prefix matching behavior and has no viable workaround.

---

Environment:

  • Claude Code version: Latest (as of November 2025)
  • Platform: Linux
  • Permission files: .claude/settings.local.json

Reproduction:

  1. Add "Bash(python3:*)" to permissions allowlist
  2. Test: python3 -c "print('hello')" → ✅ Auto-approved
  3. Test: python3 << 'EOF'\nprint('hello')\nEOF → ❌ Requires manual approval
  4. Add "Bash(python3 <<:*)" to permissions
  5. Retry step 3 → ❌ Still requires approval

Pattern matching is broken for heredocs across all commands.

cnighswonger · 8 months ago

@claude This should be labeled as a bug not as a enhancement

cnighswonger · 8 months ago

@amiramir Would you please edit the title of this and change [FEATURE] to [BUG]? Thanks!

amiramir · 8 months ago
@amiramir Would you please edit the title of this and change [FEATURE] to [BUG]? Thanks!

Done.

cnighswonger · 8 months ago

Update: Bug Persists in v2.0.31 Despite Claimed Fixes + New Related Issue

Environment:

  • Claude Code version: 2.0.31 (current as of 2025-11-16)
  • Platform: Linux

Bug Status: PERSISTS

The original heredoc pattern matching bug reported in my November 11 comment remains unfixed despite two relevant fixes in the CHANGELOG:

Version 1.0.77:

"Bash tool: Fix heredoc and multiline string escaping, improve stderr redirection handling"

Version 1.0.120:

"Fixed security vulnerability where Bash tool permission checks could be bypassed using prefix matching"

Neither fix resolved the core issue: auto-permission patterns like Bash(python3:*) still do not match heredoc commands (python3 << 'EOF'...EOF).

Confirmation

Tested today with version 2.0.31 using the following auto-permissions:

Bash(python3:*)
Bash(python:*)
Bash(python3 << 'EOF':*)
Bash(python << 'EOF':*)

Result: All heredoc-based Python commands still require manual approval. The permission matcher fails to recognize python3 << 'EOF' as matching the python3:* pattern.

---

NEW ISSUE DISCOVERED: Heredoc Content Scanning

While investigating, we discovered a related bug where the permission matcher appears to scan heredoc content for permission-like patterns, causing false-positive permission requests.

Reproduction Case:

When creating a git commit message containing documentation of auto-permissions (e.g., Bash(python:*), Bash(git:*)), the permission system treats these literal strings inside the heredoc as permission patterns, blocking execution.

Example Command:

git commit -m "$(cat <<'EOF'
Update documentation

Auto-permissions tested:
- Bash(python:*)
- Bash(git:*)
- Bash(echo:*)

All working correctly.
EOF
)"

Expected: Command executes (git commit is approved via Bash(git commit:*))

Actual: Permission request displays the commit message content and asks for approval, seemingly triggered by parsing the literal strings Bash(python:*) etc. within the heredoc body.

Impact: Cannot document auto-permission patterns in commit messages, comments, or any heredoc-based text generation without triggering false permission requests.

---

Root Cause Hypothesis

The permission matching system appears to:

  1. Fail to match heredoc syntax against command patterns (original bug)
  2. Parse heredoc content for permission-like patterns (new bug)

Both suggest the permission matcher operates at the wrong layer—parsing heredoc syntax and content rather than matching against the actual command being executed (python3, git commit, etc.).

---

Business Impact

This compounds the original workflow disruption:

  • Heredoc commands require manual approval (original bug)
  • Documenting workarounds triggers additional false approvals (new bug)
  • No viable workaround exists for scripting workflows involving inline Python/shell scripts

The agentic workflow is completely broken for any task requiring heredoc patterns.

---

Would appreciate confirmation from the Claude Code team whether:

  1. The 1.0.77/1.0.120 fixes were intended to address this issue
  2. There's a known regression between those versions and 2.0.31
  3. A proper fix is planned for the permission matching layer
cruftyoldsysadmin · 8 months ago

This still persists in 2.0.42. Claude also skips using Serena or any other mcp servers designed to get around Claude's poor file editing functionality.

cruftyoldsysadmin · 7 months ago

Writing files is the most basic functionality. Why bother at all if Claude can't manage to write files without complicated, brittle bash commands that are wrong half of the time?

This has been an ignored problem since day one.

cnighswonger · 6 months ago

Based on @lior-airis suggestion, I discovered the following workaround:

The sandbox requests read permissions for the project root directory for every heredoc created. Adding that directory to "additionalDirectories" in ~/.claude/settings.json seems to fix the entire issue.

   "additionalDirectories": [
      "<project-root-dir>/"
   ]

Its seems that the bug here is that Claude Code does not create this addition when the permission is granted the first time and, thus, continues to prompt for it.

github-actions[bot] · 5 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

cnighswonger · 5 months ago

Still a problem.

tobilg · 5 months ago

Still a problem in the latest version, and this is really bad. Neither instructions to ignore heredoc in the CLAUDE.md nor in the prompt/plan disable this, whcih breaks agent loop pattern and requires user interaction every few minutes while it originally would be able to work unattendedly for hours...

jwintersinger · 5 months ago

This seems to help at the end of my prompt:

"Avoid executing code via heredocs. Instead, write your throwaway Python code to /tmp/cc.jeff/ (create that directory if necessary) and execute it from there."

tobilg · 5 months ago
This seems to help at the end of my prompt: "Avoid executing code via heredocs. Instead, write your throwaway Python code to /tmp/cc.jeff/ (create that directory if necessary) and execute it from there."

Yes, adding it (again) to the prompt seems to help regarding the directory, but not regarding heredocs in general (I'm on 2.1.29). I think it's a parsing / validation problem with multiline heredocs, at least from the generated code I'm seeing

Da1sypetals · 5 months ago

I think it should be an issue of claude code, not claude model. claude code should be able to identify heredoc patterns and BAN that pattern. Heredoc is crazily annoying.

github-actions[bot] · 4 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

github-actions[bot] · 3 months ago

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.