From da8225744a5a60bcbba47d7d98027b8102279d38 Mon Sep 17 00:00:00 2001 From: Michel Tomas Date: Sat, 5 Sep 2026 15:41:32 +0200 Subject: [PATCH] fix(adapter-utils): consume a line continuation inside a quoted header value A backslash-newline continuation inside a double-quoted header argument ended the quoted match, so the unquoted fallback redacted only the part of the credential before the continuation. The double-quoted branch now treats the continuation as part of the value, with LF and CRLF line endings. Claude-Session: https://claude.ai/code/session_01RYigf3eMFJjey9iKRApPGE --- .../adapter-utils/src/command-redaction.test.ts | 14 ++++++++++++++ packages/adapter-utils/src/command-redaction.ts | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/adapter-utils/src/command-redaction.test.ts b/packages/adapter-utils/src/command-redaction.test.ts index b68a65ab8c..7ddb24c823 100644 --- a/packages/adapter-utils/src/command-redaction.test.ts +++ b/packages/adapter-utils/src/command-redaction.test.ts @@ -286,6 +286,20 @@ describe("redactCommandText header secrets", () => { ); }); + it("redacts across a backslash-newline continuation inside a double-quoted value", () => { + // A shell line continuation inside double quotes is part of the argument. + const input = 'curl -H "X-API-Key: abc\\\ndef" https://example.test'; + const output = redactCommandText(input); + expect(output).not.toContain("def"); + expect(output).toBe( + `curl -H "X-API-Key: ${REDACTED_COMMAND_TEXT_VALUE}" https://example.test`, + ); + const crlf = 'curl -H "X-API-Key: abc\\\r\ndef" https://example.test'; + expect(redactCommandText(crlf)).toBe( + `curl -H "X-API-Key: ${REDACTED_COMMAND_TEXT_VALUE}" https://example.test`, + ); + }); + it("redacts a backslash inside a single-quoted header value", () => { // A shell single quote has no escapes, so the backslash is part of the value. const input = String.raw`curl -H 'X-API-Key: abc\def' https://example.test`; diff --git a/packages/adapter-utils/src/command-redaction.ts b/packages/adapter-utils/src/command-redaction.ts index e401c3b55c..0a2a573c6b 100644 --- a/packages/adapter-utils/src/command-redaction.ts +++ b/packages/adapter-utils/src/command-redaction.ts @@ -47,7 +47,8 @@ const COMMAND_AUTHORIZATION_BEARER_RE = // // Each branch treats the backslash the way its quoting context does. A // double-quoted value consumes escape pairs, so an escaped quote inside the -// argument (`"X-API-Key: abc\"def"`) does not end the value early. Its opening +// argument (`"X-API-Key: abc\"def"`) does not end the value early, and neither +// does a backslash-newline line continuation. Its opening // quote must itself be unescaped, which keeps the branch off a serialized // diagnostic such as `\"X-API-Key: ...\"`, where the closing `\"` must survive. // A single-quoted value takes a backslash literally, because a shell single @@ -95,7 +96,7 @@ const COMMAND_SECRET_HEADER_UNQUOTED_VALUE_PATTERN = "`" + String.raw`]+)`; const COMMAND_SECRET_HEADER_RE = new RegExp( - String.raw`(?