(context: ValidationContext)
| 903 | } |
| 904 | |
| 905 | function validateNewlines(context: ValidationContext): PermissionResult { |
| 906 | // Use fullyUnquotedPreStrip (before stripSafeRedirections) to prevent bypasses |
| 907 | // where stripping `>/dev/null` creates a phantom backslash-newline continuation. |
| 908 | // E.g., `cmd \>/dev/null\nwhoami` → after stripping becomes `cmd \\nwhoami` |
| 909 | // which looks like a safe continuation but actually hides a second command. |
| 910 | const { fullyUnquotedPreStrip } = context |
| 911 | |
| 912 | // Check for newlines in unquoted content |
| 913 | if (!/[\n\r]/.test(fullyUnquotedPreStrip)) { |
| 914 | return { behavior: 'passthrough', message: 'No newlines' } |
| 915 | } |
| 916 | |
| 917 | // Flag any newline/CR followed by non-whitespace, EXCEPT backslash-newline |
| 918 | // continuations at word boundaries. In bash, `\<newline>` is a line |
| 919 | // continuation (both chars removed), which is safe when the backslash |
| 920 | // follows whitespace (e.g., `cmd \<newline>--flag`). Mid-word continuations |
| 921 | // like `tr\<newline>aceroute` are still flagged because they can hide |
| 922 | // dangerous command names from allowlist checks. |
| 923 | // eslint-disable-next-line custom-rules/no-lookbehind-regex -- .test() + gated by /[\n\r]/.test() above |
| 924 | const looksLikeCommand = /(?<![\s]\\)[\n\r]\s*\S/.test(fullyUnquotedPreStrip) |
| 925 | if (looksLikeCommand) { |
| 926 | logEvent('tengu_bash_security_check_triggered', { |
| 927 | checkId: BASH_SECURITY_CHECK_IDS.NEWLINES, |
| 928 | subId: 1, |
| 929 | }) |
| 930 | return { |
| 931 | behavior: 'ask', |
| 932 | message: |
| 933 | 'Command contains newlines that could separate multiple commands', |
| 934 | } |
| 935 | } |
| 936 | |
| 937 | return { |
| 938 | behavior: 'passthrough', |
| 939 | message: 'Newlines appear to be within data', |
| 940 | } |
| 941 | } |
| 942 | |
| 943 | /** |
| 944 | * SECURITY: Carriage return (\r, 0x0D) IS a misparsing concern, unlike LF. |
nothing calls this directly
no test coverage detected