MCPcopy Create free account
hub / github.com/codeaashu/claude-code / validateQuotedNewline

Function validateQuotedNewline

src/tools/BashTool/bashSecurity.ts:2109–2175  ·  view source on GitHub ↗

* Detects a newline inside a quoted string where the NEXT line would be * stripped by stripCommentLines (trimmed line starts with `#`). * * In bash, `\n` inside quotes is a literal character and part of the argument. * But stripCommentLines (called by stripSafeWrappers in bashPermissions before

(context: ValidationContext)

Source from the content-addressed store, hash-verified

2107 * permission flow at bashPermissions.ts before any line-based processing runs.
2108 */
2109function validateQuotedNewline(context: ValidationContext): PermissionResult {
2110 const { originalCommand } = context
2111
2112 // Fast path: must have both a newline byte AND a # character somewhere.
2113 // stripCommentLines only strips lines where trim().startsWith('#'), so
2114 // no # means no possible trigger.
2115 if (!originalCommand.includes('\n') || !originalCommand.includes('#')) {
2116 return { behavior: 'passthrough', message: 'No newline or no hash' }
2117 }
2118
2119 // Track quote state. Mirrors extractQuotedContent / validateCommentQuoteDesync:
2120 // - single quotes don't toggle inside double quotes
2121 // - backslash escapes the next char (but not inside single quotes)
2122 // stripCommentLines splits on '\n' (not \r), so we only treat \n as a line
2123 // separator. \r inside a line is removed by trim() and doesn't change the
2124 // trimmed-starts-with-# check.
2125 let inSingleQuote = false
2126 let inDoubleQuote = false
2127 let escaped = false
2128
2129 for (let i = 0; i < originalCommand.length; i++) {
2130 const char = originalCommand[i]
2131
2132 if (escaped) {
2133 escaped = false
2134 continue
2135 }
2136
2137 if (char === '\\' && !inSingleQuote) {
2138 escaped = true
2139 continue
2140 }
2141
2142 if (char === "'" && !inDoubleQuote) {
2143 inSingleQuote = !inSingleQuote
2144 continue
2145 }
2146
2147 if (char === '"' && !inSingleQuote) {
2148 inDoubleQuote = !inDoubleQuote
2149 continue
2150 }
2151
2152 // A newline inside quotes: the NEXT line (from bash's perspective) starts
2153 // inside a quoted string. Check if that line would be stripped by
2154 // stripCommentLines — i.e., after trim(), does it start with `#`?
2155 // This exactly mirrors: lines.filter(l => !l.trim().startsWith('#'))
2156 if (char === '\n' && (inSingleQuote || inDoubleQuote)) {
2157 const lineStart = i + 1
2158 const nextNewline = originalCommand.indexOf('\n', lineStart)
2159 const lineEnd = nextNewline === -1 ? originalCommand.length : nextNewline
2160 const nextLine = originalCommand.slice(lineStart, lineEnd)
2161 if (nextLine.trim().startsWith('#')) {
2162 logEvent('tengu_bash_security_check_triggered', {
2163 checkId: BASH_SECURITY_CHECK_IDS.QUOTED_NEWLINE,
2164 })
2165 return {
2166 behavior: 'ask',

Callers

nothing calls this directly

Calls 1

logEventFunction · 0.85

Tested by

no test coverage detected