[BUG] Multi-line bash permission patterns with heredocs corrupt settings.json

Resolved 💬 8 comments Opened Dec 29, 2025 by EmanuelFaria Closed Mar 17, 2026

[BUG] Multi-line bash permission patterns with heredocs corrupt settings.json

Description

When multi-line bash commands containing heredoc operators are added to Claude Code's permission system, they corrupt settings.json with "Unmatched ' in Bash pattern" errors, completely blocking all Claude Code operations.

Environment

  • Claude Code Version: 2.0.54+
  • OS: macOS (also affects other platforms)
  • Project Type: All

Problem Statement

Symptoms:

Settings Error

 /path/to/.claude/settings.local.json
  └ permissions
    └ allow
      └ "Bash(...multi-line heredoc...)" : Unmatched ' in Bash pattern.
        Ensure all quotes are properly paired

 Files with errors are skipped entirely, not just the invalid settings.

Root Cause:
Multi-line bash commands (691 chars, 24 newlines) with heredoc operators bypass validation and get added to settings.json, causing JSON parse errors.

Steps to Reproduce

  1. Have a working Claude Code installation with .claude/settings.local.json
  2. Attempt to add a multi-line bash pattern with heredoc
  3. This pattern gets added to settings.json (via permission prompt or direct edit)
  4. Claude Code fails to start with "Unmatched ' in Bash pattern" error
  5. All Claude Code operations blocked until manual JSON editing

Expected Behavior

Multi-line commands with heredocs should be rejected during validation with a clear error message explaining why they're invalid.

Actual Behavior

Multi-line heredoc patterns are accepted and corrupt settings.json, blocking all operations.

Impact

  • Severity: Critical - Blocks entire Claude Code session
  • User Impact: Complete loss of access until manual JSON repair
  • Workaround: Manual JSON editing required (non-trivial for non-developers)
  • Frequency: Rare but catastrophic when it occurs

Malformed Entry Characteristics

The problematic entry was:

  • 691 characters (should reject >500 chars)
  • 24 newlines (multi-line command)
  • Heredoc operator (<<)
  • Starts with comment (#)
  • Shell keywords (try, tell, etc.)

All of these should trigger validation rejection but currently don't.

Validation Gap

Claude Code currently lacks comprehensive validation for permission patterns. Needed checks include:

  1. Parentheses balancing (currently checked)
  2. Command substitution $(...) (currently checked)
  3. Newlines/multi-line commands (NOT checked)
  4. Heredoc operators <<, <<< (NOT checked)
  5. Shell constructs if, for, while (NOT checked)
  6. Comment patterns starting with # (NOT checked)
  7. Length limits >500 chars (NOT checked)
  8. Quote balancing single+double (NOT checked)

Suggested Fix

Add comprehensive permission pattern validation before writing to settings.json:

def validate_permission_pattern(pattern: str) -> dict:
    """Validate permission pattern before adding to settings."""

    # Check for newlines (multi-line commands)
    if '\\n' in pattern or '\\r' in pattern:
        return {"valid": False, "reason": "Multi-line commands not allowed"}

    # Check for heredoc operators
    if '<<' in pattern:
        return {"valid": False, "reason": "Heredoc operators not allowed"}

    # Check for length
    if len(pattern) > 500:
        return {"valid": False, "reason": f"Pattern too long ({len(pattern)} chars, max 500)"}

    # Check for shell constructs
    if re.search(r'\\b(if|for|while|do|then|else|fi)\\b', pattern):
        return {"valid": False, "reason": "Shell constructs not allowed"}

    # Check for comments
    if pattern.strip().startswith('Bash(#'):
        return {"valid": False, "reason": "Comment patterns not allowed"}

    # Existing checks...
    return {"valid": True}

Related Issues

  • #5710 - "Don't Ask Again" Overwrites Entire Permissions Array (different but related)
  • #7300 - Claude Code writes broken Permission Syntax (different pattern type)

Additional Context

User Workarounds:

  • chmod 444 .claude/settings.local.json (prevents corruption but breaks permission additions)
  • Manual JSON editing (requires technical knowledge)
  • Git checkout to restore (if settings are version-controlled)

Detection:
This issue may be related to how permission patterns are captured from bash commands. If Claude is executing multi-line heredocs and then trying to save the entire command as a permission pattern, the pattern extraction logic needs to be enhanced to reject such patterns upfront.

Reproduction Rate

  • Low frequency (requires specific multi-line bash commands)
  • High impact (complete session block when it occurs)
  • 100% reproducible with malformed patterns

---

Note: This issue has been observed in the wild and required creating custom PreToolUse hooks to prevent settings.json corruption. The validation logic described in "Suggested Fix" has been tested against 600+ existing permission patterns with zero false positives.

View original on GitHub ↗

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