"Always allow" on multi-line Bash commands creates junk permission entries
Description
When approving multi-line Bash commands (for-loops, if-statements, heredocs) with "Always allow", each line of the command is saved as a separate permission entry in settings.local.json, creating dozens of useless/broken entries.
Steps to reproduce
- Run Claude Code and let it execute a multi-line Bash command, e.g.:
``bash``
for icon in a b c; do
echo "$icon"
done
- Click "Always allow" when prompted
- Check
.claude/settings.local.json
Expected behavior
A single, sensible permission pattern is saved (or multi-line commands are excluded from "Always allow").
Actual behavior
Each line is saved as a separate entry:
"Bash(for icon in a b c)",
"Bash(do)",
"Bash(echo:*)",
"Bash(done)"
Additional problematic patterns observed:
- If-statement fragments:
Bash(then),Bash(else),Bash(fi)saved as individual entries __NEW_LINE_*entries: Internal newline encoding leaks into settings, e.g.Bash(__NEW_LINE_f740ed307bd5cd58__ echo "=== Button SCSS ===")- Heredoc content saved verbatim:
cat << 'ENDOFFILE'commands save the entire file content (hundreds of lines of markdown) as a single permission pattern string, e.g.Bash(/path/to/file.md << 'ENDOFFILE'\n# Phase 4: Component Verification...ENDOFFILE) - These heredoc entries also trigger
/doctorwarnings:The :* pattern must be at the end
Impact
Over several sessions, settings.local.json accumulated 92 entries, ~60 of which were junk. The heredoc entries alone were thousands of characters each. The /doctor command flags some of these as invalid patterns.
Environment
- Claude Code (CLI)
- macOS (Darwin 25.2.0)
Suggested fix
Options (not mutually exclusive):
- Don't offer "Always allow" for multi-line Bash commands
- If saving, save the full command as a single entry rather than splitting on newlines
- Sanitize/skip entries that are clearly fragments (
do,then,else,fi,done) - Never save heredoc content as permission patterns
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗