Heredoc-containing Bash commands split into multiple permission entries

Resolved 💬 3 comments Opened Feb 14, 2026 by rhart696 Closed Feb 18, 2026

Description

When a user approves a Bash command containing a heredoc (e.g., git commit -m "$(cat <<'EOF'...)""), the permission parser splits on newlines and saves each line of the heredoc body as a separate permission entry in settings.local.json.

Expected Behavior

The entire command should be saved as a single permission entry, or the heredoc should be collapsed into a wildcard pattern (e.g., Bash(git commit *)).

Actual Behavior

A single git commit approval creates 10+ entries, one per line of the commit message body. Examples of corrupted entries found:

"Bash(MY ecosystem?\" Leading to either premature implementation...)",
"Bash(- Layer 1: Permission deny rules...)",
"Bash(versions\" error during migration script execution...)",
"Bash(__NEW_LINE_e5fdbe8e55f17f4e__ echo \"\")"

Internal __NEW_LINE_<hash>__ markers also leak into saved permissions.

Reproduction

  1. Start a Claude Code session
  2. Ask Claude to make a git commit with a multi-line message using the HEREDOC pattern:

```bash
git commit -m "$(cat <<'EOF'
Some commit title

Multi-line body with details.

Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)"
```

  1. When prompted, approve the command ("Always allow")
  2. Inspect <project>/.claude/settings.local.json — each line of the commit message is a separate entry

Impact

  • Permission list bloats with invalid entries (observed 43 corrupted entries in a single session)
  • Entries like Bash(for:*), Bash(EOF), Bash(exec) could inadvertently grant overly broad permissions
  • Ongoing issue: corruption recurs every session since heredoc commits are common

Workaround

We've built governance hooks that detect and auto-repair these entries post-write (permission_validator.py, settings_guard.py, permission_auto_sanitizer.py), but this is reactive — corruption still hits disk before being cleaned up.

Environment

  • Claude Code CLI (latest as of Feb 2026)
  • WSL2, Ubuntu
  • Occurs with both settings.local.json (project) and could affect settings.json (global)

View original on GitHub ↗

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