From 80854aac32ca6bface0aadbf76959e09f1b2dfc8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 13:13:12 +0000 Subject: [PATCH] fix(ansi): prevent terminal injection by supporting String Terminator (ST) in OSC regex Co-authored-by: hongymagic <302730+hongymagic@users.noreply.github.com> --- .jules/sentinel.md | 5 +++++ src/ansi.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index e644cad..0dc5b06 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -39,3 +39,8 @@ **Vulnerability:** The `filterSensitiveFields` function in `src/providers/index.ts` used a manual recursive loop to drop sensitive keys, but it failed to recurse into arrays. If a configuration object contained an array with sensitive nested objects, those secrets would be leaked in debug logs. **Learning:** Manual object traversal for redaction is prone to edge cases (like arrays or circular references). **Prevention:** Use a custom replacer function with `JSON.stringify` to safely and completely redact sensitive fields across all nested structures. + +## 2026-05-31 - Terminal Injection via Incomplete OSC Terminator regex +**Vulnerability:** The regex in `src/ansi.ts` for stripping ANSI sequences only accounted for `\u0007` (Bell) as the Operating System Command (OSC) sequence terminator. It did not support the String Terminator (ST) `\u001B\`. An attacker could inject OSC sequences terminated by ST to bypass the ANSI stripping, leading to terminal injection. +**Learning:** Security-critical regexes meant to strip escape sequences must handle all standard terminators (like both BEL and ST) to prevent bypass. +**Prevention:** Update `ANSI_REGEX` to match `(?:\\u0007|\\u001B\\\\)` to cover both terminators. diff --git a/src/ansi.ts b/src/ansi.ts index dd2c205..a5a95e5 100644 --- a/src/ansi.ts +++ b/src/ansi.ts @@ -2,7 +2,7 @@ // eslint-disable-next-line no-control-regex const ANSI_REGEX = new RegExp( [ - "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", + "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\\\))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", ].join("|"), "g",