From 51f8c7181d158095c375af5ecc51521b39183a64 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 15:20:29 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]?= =?UTF-8?q?=20Fix=20Terminal=20Injection=20via=20ANSI=20OSC=20sequences=20?= =?UTF-8?q?with=20ST=20terminator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚨 Severity: HIGH * 💡 Vulnerability: ANSI OSC sequences ending with the String Terminator (ST, \u001B\\) were not matched by the ANSI_REGEX, meaning they bypassed the stripAnsi filter. * 🎯 Impact: A malicious response from an AI model could include an unstripped OSC sequence like `\x1B]8;;http://malicious.com\x1B\\Malicious Link\x1B]8;;\x1B\\` to render disguised hyperlinks or manipulate the terminal. * 🔧 Fix: Updated the ANSI_REGEX in `src/ansi.ts` to match both `\u0007` (BEL) and `\u001B\\` (ST). * ✅ Verification: Added a test case to `tests/ansi_security.test.ts` to assert that OSC sequences ending with ST are completely stripped. Co-authored-by: hongymagic <302730+hongymagic@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ src/ansi.ts | 2 +- tests/ansi_security.test.ts | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index e644cad..ef178cc 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -39,3 +39,7 @@ **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-11 - Terminal Injection via ANSI OSC ST sequences +**Vulnerability:** ANSI_REGEX in `src/ansi.ts` failed to match OSC sequences terminated with the String Terminator (ST, `\u001B\\`), leaving them unstripped. `sanitizeForTerminal` then translated `\x1B` to the literal string `\x1B`, meaning the payload was bypassed entirely and printed to the terminal. +**Learning:** Standard library `ansi-regex` packages and implementations often omit or poorly handle the String Terminator (ST) sequence, assuming OSCs only end in `\x07` (BEL). +**Prevention:** When stripping ANSI escapes, ensure OSC (Operating System Command) regexes explicitly capture the String Terminator `(?:\u0007|\u001B\\)` to completely sanitize potentially malicious sequences like terminal hyperlinks. 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", diff --git a/tests/ansi_security.test.ts b/tests/ansi_security.test.ts index 3f0993c..20e2fb6 100644 --- a/tests/ansi_security.test.ts +++ b/tests/ansi_security.test.ts @@ -113,6 +113,11 @@ describe("sanitizeForClipboard", () => { expect(sanitizeForClipboard(input)).toBe("Red Text"); }); + test("strips ANSI OSC sequences with String Terminator (ST)", () => { + const input = "\u001b]8;;http://malicious.com\u001b\\Malicious Link\u001b]8;;\u001b\\"; + expect(sanitizeForClipboard(input)).toBe("Malicious Link"); + }); + test("preserves tab and newline; normalises CRLF to LF", () => { expect(sanitizeForClipboard("Line 1\n\tIndented\r\nLine 2")).toBe( "Line 1\n\tIndented\nLine 2", From caa11d66855bd36fd30226f2fb683d1904c5cd21 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 15:27:26 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]?= =?UTF-8?q?=20Fix=20Terminal=20Injection=20via=20ANSI=20OSC=20sequences=20?= =?UTF-8?q?with=20ST=20terminator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚨 Severity: HIGH * 💡 Vulnerability: ANSI OSC sequences ending with the String Terminator (ST, \u001B\\) were not matched by the ANSI_REGEX, meaning they bypassed the stripAnsi filter. * 🎯 Impact: A malicious response from an AI model could include an unstripped OSC sequence like `\x1B]8;;http://malicious.com\x1B\\Malicious Link\x1B]8;;\x1B\\` to render disguised hyperlinks or manipulate the terminal. * 🔧 Fix: Updated the ANSI_REGEX in `src/ansi.ts` to match both `\u0007` (BEL) and `\u001B\\` (ST). * ✅ Verification: Added a test case to `tests/ansi_security.test.ts` to assert that OSC sequences ending with ST are completely stripped. Co-authored-by: hongymagic <302730+hongymagic@users.noreply.github.com> --- tests/ansi_security.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ansi_security.test.ts b/tests/ansi_security.test.ts index 20e2fb6..f75b23a 100644 --- a/tests/ansi_security.test.ts +++ b/tests/ansi_security.test.ts @@ -114,7 +114,8 @@ describe("sanitizeForClipboard", () => { }); test("strips ANSI OSC sequences with String Terminator (ST)", () => { - const input = "\u001b]8;;http://malicious.com\u001b\\Malicious Link\u001b]8;;\u001b\\"; + const input = + "\u001b]8;;http://malicious.com\u001b\\Malicious Link\u001b]8;;\u001b\\"; expect(sanitizeForClipboard(input)).toBe("Malicious Link"); });