Bug: Claude directly edits settings.local.json with malformed permission patterns
Resolved 💬 3 comments Opened Feb 4, 2026 by hrp Closed Feb 8, 2026
Description
When approving a complex Bash command (e.g., gh pr edit with a heredoc body) through Claude Code's permission prompt, the system saves the entire literal command as a permission pattern instead of extracting a sensible pattern. This creates an invalid entry that fails validation and prevents Claude Code from starting.
Steps to Reproduce
- Have Claude run a complex command like:
``bash``
gh pr edit 12345 --body "$(cat <<'EOF'
Some multiline content...
EOF
)"
- Approve the command with "Always allow"
- Claude Code saves the full literal command to
settings.local.json - On next startup, the settings file fails validation
Actual Behavior
The permission system saved an entry like this to settings.local.json:
"Bash(gh pr edit 12345 --body \"$\\(cat <<''EOF''\n### Some title\n\nSome content with special characters and newlines...\nEOF\n\\)\")"
On startup, this causes the error:
The :* pattern must be at the end. Move :* to the end for prefix matching, or use * for wildcard matching.
The settings file is then skipped entirely, losing all configured permissions.
Expected Behavior
- The permission system should extract a sensible pattern from complex commands (e.g.,
Bash(gh pr edit:*)orBash(gh pr edit *)) - The system should never write an invalid pattern that fails its own validation
- If pattern extraction is uncertain, it should perhaps prompt the user for what pattern to save
Environment
- Claude Code CLI
- macOS
Impact
- Settings file becomes invalid and is skipped on startup
- User loses all configured permissions until manually fixed
- User has to identify and remove the malformed entries
Suggested Fix
- Add validation before writing patterns to settings files - never write something that would fail validation on read
- Improve pattern extraction for complex commands with heredocs, subshells, quotes, etc.
- Consider falling back to a simple prefix pattern when the command is too complex to parse
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗