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

claude-code / .claude / bash-permission-bug-analysis.md
177 lines · 5.0 KBPreviewCodeRaw
1# Bash Permission Serialization Bug Analysis
2
3## Bug Description
4
5When 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
81. Have Claude run a bash command containing quotes (e.g., arithmetic with quoted strings)
92. When permission is requested, click "Always Allow"
103. A malformed permission rule may be saved to `settings.local.json`
114. 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
301. **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
352. **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
493. **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
584. **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
695. **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
83Validation 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
92Add validation in `_A1` before saving:
93
94```javascript
95function _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
115Add validation when creating suggestions:
116
117```javascript
118function 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
139If the command has unbalanced quotes, try to fix or reject it:
140
141```javascript
142function 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
1591. The command parsing/reconstruction in `VJ7` is complex and may have edge cases where commands are not properly reconstructed
160
1612. The `KE0` function uses quote markers (`__DOUBLE_QUOTE__`, `__SINGLE_QUOTE__`) for parsing which may not be fully restored in all cases
162
1633. For piped commands, each segment is processed separately, increasing the chance of parsing errors
164
165## Recommended Fix Priority
166
1671. **Immediate**: Add validation before saving in `_A1` or `$v` functions
1682. **Short-term**: Add better error handling when command parsing fails
1693. **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
177These suggest this area of the code has had issues before.