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

Function hasBackslashEscapedOperator

src/tools/BashTool/bashSecurity.ts:1631–1694  ·  view source on GitHub ↗
(command: string)

Source from the content-addressed store, hash-verified

1629const SHELL_OPERATORS = new Set([';', '|', '&', '<', '>'])
1630
1631function hasBackslashEscapedOperator(command: string): boolean {
1632 let inSingleQuote = false
1633 let inDoubleQuote = false
1634
1635 for (let i = 0; i < command.length; i++) {
1636 const char = command[i]
1637
1638 // SECURITY: Handle backslash FIRST, before quote toggles. In bash, inside
1639 // double quotes, `\"` is an escape sequence producing a literal `"` — it
1640 // does NOT close the quote. If we process quote toggles first, `\"` inside
1641 // `"..."` desyncs the tracker:
1642 // - `\` is ignored (gated by !inDoubleQuote)
1643 // - `"` toggles inDoubleQuote to FALSE (wrong — bash says still inside)
1644 // - next `"` (the real closing quote) toggles BACK to TRUE — locked desync
1645 // - subsequent `\;` is missed because !inDoubleQuote is false
1646 // Exploit: `tac "x\"y" \; echo ~/.ssh/id_rsa` — bash runs ONE tac reading
1647 // all args as files (leaking id_rsa), but desynced tracker misses `\;` and
1648 // splitCommand's double-parse normalization "sees" two safe commands.
1649 //
1650 // Fix structure matches hasBackslashEscapedWhitespace (which was correctly
1651 // fixed for this in commit prior to d000dfe84e): backslash check first,
1652 // gated only by !inSingleQuote (since backslash IS literal inside '...'),
1653 // unconditional i++ to skip the escaped char even inside double quotes.
1654 if (char === '\\' && !inSingleQuote) {
1655 // Only flag \<operator> when OUTSIDE double quotes (inside double quotes,
1656 // operators like ;|&<> are already not special, so \; is harmless there).
1657 if (!inDoubleQuote) {
1658 const nextChar = command[i + 1]
1659 if (nextChar && SHELL_OPERATORS.has(nextChar)) {
1660 return true
1661 }
1662 }
1663 // Skip the escaped character unconditionally. Inside double quotes, this
1664 // correctly consumes backslash pairs: `"x\\"` → pos 6 (`\`) skips pos 7
1665 // (`\`), then pos 8 (`"`) toggles inDoubleQuote off correctly. Without
1666 // unconditional skip, pos 7 would see `\`, see pos 8 (`"`) as nextChar,
1667 // skip it, and the closing quote would NEVER toggle inDoubleQuote —
1668 // permanently desyncing and missing subsequent `\;` outside quotes.
1669 // Exploit: `cat "x\\" \; echo /etc/passwd` — bash reads /etc/passwd.
1670 //
1671 // This correctly handles backslash parity: odd-count `\;` (1, 3, 5...)
1672 // is flagged (the unpaired `\` before `;` is detected). Even-count `\\;`
1673 // (2, 4...) is NOT flagged, which is CORRECT — bash treats `\\` as
1674 // literal `\` and `;` as a separator, so splitCommand handles it
1675 // normally (no double-parse bug). This matches
1676 // hasBackslashEscapedWhitespace line ~1340.
1677 i++
1678 continue
1679 }
1680
1681 // Quote toggles come AFTER backslash handling (backslash already skipped
1682 // any escaped quote char, so these toggles only fire on unescaped quotes).
1683 if (char === "'" && !inDoubleQuote) {
1684 inSingleQuote = !inSingleQuote
1685 continue
1686 }
1687 if (char === '"' && !inSingleQuote) {
1688 inDoubleQuote = !inDoubleQuote

Callers 1

Calls 1

hasMethod · 0.45

Tested by

no test coverage detected