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..f75b23a 100644 --- a/tests/ansi_security.test.ts +++ b/tests/ansi_security.test.ts @@ -113,6 +113,12 @@ 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",