mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 06:57:26 +00:00
fix(secrets): harden api key normalization for ByteString headers
This commit is contained in:
35
src/utils/normalize-secret-input.test.ts
Normal file
35
src/utils/normalize-secret-input.test.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeOptionalSecretInput, normalizeSecretInput } from "./normalize-secret-input.js";
|
||||
|
||||
describe("normalizeSecretInput", () => {
|
||||
it("returns empty string for non-string values", () => {
|
||||
expect(normalizeSecretInput(undefined)).toBe("");
|
||||
expect(normalizeSecretInput(null)).toBe("");
|
||||
expect(normalizeSecretInput(123)).toBe("");
|
||||
expect(normalizeSecretInput({})).toBe("");
|
||||
});
|
||||
|
||||
it("strips embedded line breaks and surrounding whitespace", () => {
|
||||
expect(normalizeSecretInput(" sk-\r\nabc\n123 ")).toBe("sk-abc123");
|
||||
});
|
||||
|
||||
it("drops non-Latin1 code points that can break HTTP ByteString headers", () => {
|
||||
// U+0417 (Cyrillic З) and U+2502 (box drawing │) are > 255.
|
||||
expect(normalizeSecretInput("key-\u0417\u2502-token")).toBe("key--token");
|
||||
});
|
||||
|
||||
it("preserves Latin-1 characters and internal spaces", () => {
|
||||
expect(normalizeSecretInput(" café token ")).toBe("café token");
|
||||
});
|
||||
});
|
||||
|
||||
describe("normalizeOptionalSecretInput", () => {
|
||||
it("returns undefined when normalized value is empty", () => {
|
||||
expect(normalizeOptionalSecretInput(" \r\n ")).toBeUndefined();
|
||||
expect(normalizeOptionalSecretInput("\u0417\u2502")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns normalized value when non-empty", () => {
|
||||
expect(normalizeOptionalSecretInput(" key-\u0417 ")).toBe("key-");
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,12 @@
|
||||
* Common footgun: line breaks (especially `\r`) embedded in API keys/tokens.
|
||||
* We strip line breaks anywhere, then trim whitespace at the ends.
|
||||
*
|
||||
* Another frequent source of runtime failures is rich-text/Unicode artifacts
|
||||
* (smart punctuation, box-drawing chars, etc.) pasted into API keys. These can
|
||||
* break HTTP header construction (`ByteString` violations). Drop non-Latin1
|
||||
* code points so malformed keys fail as auth errors instead of crashing request
|
||||
* setup.
|
||||
*
|
||||
* Intentionally does NOT remove ordinary spaces inside the string to avoid
|
||||
* silently altering "Bearer <token>" style values.
|
||||
*/
|
||||
@@ -11,7 +17,15 @@ export function normalizeSecretInput(value: unknown): string {
|
||||
if (typeof value !== "string") {
|
||||
return "";
|
||||
}
|
||||
return value.replace(/[\r\n\u2028\u2029]+/g, "").trim();
|
||||
const collapsed = value.replace(/[\r\n\u2028\u2029]+/g, "");
|
||||
let latin1Only = "";
|
||||
for (const char of collapsed) {
|
||||
const codePoint = char.codePointAt(0);
|
||||
if (typeof codePoint === "number" && codePoint <= 0xff) {
|
||||
latin1Only += char;
|
||||
}
|
||||
}
|
||||
return latin1Only.trim();
|
||||
}
|
||||
|
||||
export function normalizeOptionalSecretInput(value: unknown): string | undefined {
|
||||
|
||||
Reference in New Issue
Block a user