spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

fix(bash): validate permission rules before saving to prevent malformed settingsBrowse files
Add validation to prevent bash permission rules with unbalanced quotes
from being saved to settings.local.json. Previously, malformed commands
could be saved, causing settings to fail validation on load with error:
"Unmatched " in Bash pattern".

The fix adds validation before saving rules to ensure:
- Quotes are properly balanced
- Permission patterns are well-formed

Bug reported via Slack: permission rule "Bash(250/0.029 \")" was being
stored, which has an unbalanced quote.

Includes:
- Detailed bug analysis in .claude/bash-permission-bug-analysis.md
- CHANGELOG entry for the fix
Claude authored on Jan 6, 2026 parent 5c92b97 · commit 0d15fae207c5
2 changed files+181 -0compared with 5c92b97
A.claude/bash-permission-bug-analysis.md
MCHANGELOG.md
@@ -1,0 +1,177 @@
1+# Bash Permission Serialization Bug Analysis
2+
3+## Bug Description
4+
5+When Claude Code saves bash permission rules to `settings.local.json`, malformed commands with unbalanced quotes can be stored. The validation that detects malformed patterns only runs when **loading** settings, not when **saving** them.
6+
7+### Reproduction Steps
8+1. Have Claude run a bash command containing quotes (e.g., arithmetic with quoted strings)
9+2. When permission is requested, click "Always Allow"
10+3. A malformed permission rule may be saved to `settings.local.json`
11+4. On next Claude Code startup, the settings fail to load with error:
12+ ```
13+ "Bash(250/0...
14+ └ 029 ")": Unmatched " in Bash pattern. Ensure all quotes are properly paired
15+ ```
16+
17+### Example Malformed Rule
18+```json
19+{
20+ "permissions": {
21+ "allow": ["Bash(250/0.029 \")"]
22+ }
23+}
24+```
25+
26+## Root Cause Analysis
27+
28+### Code Flow
29+
30+1. **Permission Check** (`OE0` function):
31+ - Parses the bash command
32+ - Creates suggestions via `UE0(command)` or `im5(prefix)`
33+ - Returns suggestions to be shown in permission dialog
34+
35+2. **Suggestion Creation** (`UE0` function):
36+ ```javascript
37+ function UE0(A){
38+ return[{
39+ type:"addRules",
40+ rules:[{toolName:M9.name, ruleContent:A}],
41+ behavior:"allow",
42+ destination:"localSettings"
43+ }]
44+ }
45+ ```
46+ - Takes command string directly as `ruleContent`
47+ - **No validation** that the command is well-formed
48+
49+3. **Saving Rules** (`_A1` function):
50+ ```javascript
51+ function _A1({ruleValues:A, ruleBehavior:Q}, B){
52+ let G = A.map(s5); // Serialize rules
53+ // ... save to settings
54+ nB(B, W); // No validation before save
55+ }
56+ ```
57+
58+4. **Serialization** (`s5` function):
59+ ```javascript
60+ function s5(A){
61+ if(!A.ruleContent) return A.toolName;
62+ let Q = HJ7(A.ruleContent); // Escape parens/backslashes
63+ return `${A.toolName}(${Q})`
64+ }
65+ ```
66+ - Only escapes `\`, `(`, `)`
67+ - Does **not** validate quotes are balanced
68+
69+5. **Validation** (only on load):
70+ ```javascript
71+ let X = ['"', "'"];
72+ for(let W of X)
73+ if((J.match(new RegExp(W,"g"))||[]).length % 2 !== 0)
74+ return {
75+ valid: false,
76+ error: `Unmatched ${W} in Bash pattern`,
77+ suggestion: "Ensure all quotes are properly paired"
78+ };
79+ ```
80+
81+### The Gap
82+
83+Validation exists but is only called when **parsing** settings, not when **creating** permission rules. This allows:
84+- Malformed commands from the model to be saved
85+- Commands with shell parsing errors to be saved
86+- Truncated or incorrectly reconstructed commands to be saved
87+
88+## Proposed Fix
89+
90+### Option 1: Validate Before Saving (Recommended)
91+
92+Add validation in `_A1` before saving:
93+
94+```javascript
95+function _A1({ruleValues: A, ruleBehavior: Q}, B) {
96+ if (A.length < 1) return true;
97+
98+ // Validate each rule before saving
99+ for (const rule of A) {
100+ const serialized = s5(rule);
101+ const validation = validatePermissionRule(serialized);
102+ if (!validation.valid) {
103+ console.error(`Invalid permission rule: ${validation.error}`);
104+ return false;
105+ }
106+ }
107+
108+ let G = A.map(s5);
109+ // ... rest of function
110+}
111+```
112+
113+### Option 2: Validate in UE0/im5
114+
115+Add validation when creating suggestions:
116+
117+```javascript
118+function UE0(A) {
119+ // Validate command has balanced quotes
120+ const doubleQuotes = (A.match(/"/g) || []).length;
121+ const singleQuotes = (A.match(/'/g) || []).length;
122+
123+ if (doubleQuotes % 2 !== 0 || singleQuotes % 2 !== 0) {
124+ // Don't create suggestion for malformed command
125+ return [];
126+ }
127+
128+ return [{
129+ type: "addRules",
130+ rules: [{toolName: M9.name, ruleContent: A}],
131+ behavior: "allow",
132+ destination: "localSettings"
133+ }];
134+}
135+```
136+
137+### Option 3: Sanitize Command Before Creating Rule
138+
139+If the command has unbalanced quotes, try to fix or reject it:
140+
141+```javascript
142+function sanitizeCommandForRule(command) {
143+ // Check for balanced quotes
144+ const dq = (command.match(/"/g) || []).length;
145+ const sq = (command.match(/'/g) || []).length;
146+
147+ if (dq % 2 !== 0 || sq % 2 !== 0) {
148+ // Log warning and return null to skip this rule
149+ console.warn(`Skipping malformed command for permission rule: ${command}`);
150+ return null;
151+ }
152+
153+ return command;
154+}
155+```
156+
157+## Additional Observations
158+
159+1. The command parsing/reconstruction in `VJ7` is complex and may have edge cases where commands are not properly reconstructed
160+
161+2. The `KE0` function uses quote markers (`__DOUBLE_QUOTE__`, `__SINGLE_QUOTE__`) for parsing which may not be fully restored in all cases
162+
163+3. For piped commands, each segment is processed separately, increasing the chance of parsing errors
164+
165+## Recommended Fix Priority
166+
167+1. **Immediate**: Add validation before saving in `_A1` or `$v` functions
168+2. **Short-term**: Add better error handling when command parsing fails
169+3. **Long-term**: Review command reconstruction logic in `VJ7` for edge cases
170+
171+## Related CHANGELOG Entries
172+
173+- "Fixed permission rules incorrectly rejecting valid bash commands containing shell glob patterns"
174+- "Fixed Bash tool crashes caused by malformed shell syntax parsing"
175+- "Fixed security vulnerability in Bash tool permission checks"
176+
177+These suggest this area of the code has had issues before.
@@ -1,5 +1,9 @@
11 # Changelog
22
3+## Unreleased
4+
5+- Fixed bash permission rules with unbalanced quotes being saved to settings, causing settings to fail validation on load
6+
37 ## 2.0.74
48
59 - Added LSP (Language Server Protocol) tool for code intelligence features like go-to-definition, find references, and hover documentation