MCPcopy Index your code
hub / github.com/codeaashu/claude-code / hasMalformedTokens

Function hasMalformedTokens

src/utils/bash/shellQuote.ts:117–176  ·  view source on GitHub ↗
(
  command: string,
  parsed: ParseEntry[],
)

Source from the content-addressed store, hash-verified

115 * shell-quote's correct parsing of ambiguous input can be exploited.
116 */
117export function hasMalformedTokens(
118 command: string,
119 parsed: ParseEntry[],
120): boolean {
121 // Check for unterminated quotes in the original command. shell-quote drops
122 // an unmatched quote without leaving any trace in the tokens, so this must
123 // inspect the raw string. Walk with bash semantics: backslash escapes the
124 // next char outside single-quotes; no escapes inside single-quotes.
125 let inSingle = false
126 let inDouble = false
127 let doubleCount = 0
128 let singleCount = 0
129 for (let i = 0; i < command.length; i++) {
130 const c = command[i]
131 if (c === '\\' && !inSingle) {
132 i++
133 continue
134 }
135 if (c === '"' && !inSingle) {
136 doubleCount++
137 inDouble = !inDouble
138 } else if (c === "'" && !inDouble) {
139 singleCount++
140 inSingle = !inSingle
141 }
142 }
143 if (doubleCount % 2 !== 0 || singleCount % 2 !== 0) return true
144
145 for (const entry of parsed) {
146 if (typeof entry !== 'string') continue
147
148 // Check for unbalanced curly braces
149 const openBraces = (entry.match(/{/g) || []).length
150 const closeBraces = (entry.match(/}/g) || []).length
151 if (openBraces !== closeBraces) return true
152
153 // Check for unbalanced parentheses
154 const openParens = (entry.match(/\(/g) || []).length
155 const closeParens = (entry.match(/\)/g) || []).length
156 if (openParens !== closeParens) return true
157
158 // Check for unbalanced square brackets
159 const openBrackets = (entry.match(/\[/g) || []).length
160 const closeBrackets = (entry.match(/\]/g) || []).length
161 if (openBrackets !== closeBrackets) return true
162
163 // Check for unbalanced double quotes
164 // Count quotes that aren't escaped (preceded by backslash)
165 // A token with an odd number of unescaped quotes is malformed
166 // eslint-disable-next-line custom-rules/no-lookbehind-regex -- gated by hasCommandSeparator check at caller, runs on short per-token strings
167 const doubleQuotes = entry.match(/(?<!\\)"/g) || []
168 if (doubleQuotes.length % 2 !== 0) return true
169
170 // Check for unbalanced single quotes
171 // eslint-disable-next-line custom-rules/no-lookbehind-regex -- same as above
172 const singleQuotes = entry.match(/(?<!\\)'/g) || []
173 if (singleQuotes.length % 2 !== 0) return true
174 }

Callers 2

rearrangePipeCommandFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected