fix(auth): strip controls from masked API keys (#96445)

* fix(auth): strip controls from masked API keys

* test(auth): cover DEL and C1 masked key controls

* chore: retrigger PR checks

---------

Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
(cherry picked from commit 2906d6c38f)
This commit is contained in:
lin-hongkuan
2026-06-30 02:15:55 +08:00
committed by Dallin Romney
parent b61ed3180f
commit 442099d9b2
2 changed files with 20 additions and 1 deletions
+7
View File
@@ -18,4 +18,11 @@ describe("maskApiKey", () => {
it("masks long values with first and last 8 chars", () => {
expect(maskApiKey("1234567890abcdefghijklmnop")).toBe("12345678...ijklmnop"); // pragma: allowlist secret
});
it("strips control characters before masking diagnostic output", () => {
expect(maskApiKey("abcd\nefghijklmnop")).toBe("ab...op");
expect(maskApiKey("abcd\u0000efghijklmnop")).toBe("ab...op");
expect(maskApiKey("abcd\u007f\u0085efghijklmnop")).toBe("ab...op");
expect(maskApiKey("\u0000\n")).toBe("missing");
});
});
+13 -1
View File
@@ -1,6 +1,6 @@
/** Masks credential-like values for diagnostics while preserving enough prefix/suffix to identify them. */
export const maskApiKey = (value: string): string => {
const trimmed = value.trim();
const trimmed = stripControlCharacters(value).trim();
if (!trimmed) {
return "missing";
}
@@ -12,3 +12,15 @@ export const maskApiKey = (value: string): string => {
}
return `${trimmed.slice(0, 8)}...${trimmed.slice(-8)}`;
};
function stripControlCharacters(value: string): string {
let out = "";
for (const char of value) {
const code = char.charCodeAt(0);
const isControl = (code >= 0x00 && code <= 0x1f) || (code >= 0x7f && code <= 0x9f);
if (!isControl) {
out += char;
}
}
return out;
}