diff --git a/CHANGELOG.md b/CHANGELOG.md index d599d0ab264..ec2198d0a55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Docs: https://docs.openclaw.ai - Gateway/approvals: let loopback token/password-backed native approval clients resolve exec approvals without attaching stale paired Gateway identities, while remote and unauthenticated approval clients keep normal device identity behavior. (#74472) - Gateway/config: include rejected validation paths in foreground and service last-known-good recovery logs plus main-agent notices, so unsupported direct edits explain which key caused restore instead of looking like silent reversion. Fixes #75060. Thanks @amknight. - Plugins/runtime-deps: hash the OS-canonical `packageRoot` via `fs.realpathSync.native` (with `path.resolve` fallback) when computing the bundled runtime-deps stage key, so loader and channel `bundled-root` callers no longer derive divergent stage directories under `~/.openclaw/plugin-runtime-deps/openclaw--/` and bundled channels stop failing with `ENOENT` on shared dist chunks under Windows npm symlinks, junctions, or PM2 multi-instance worker layouts. Fixes #74963. (#75048) Thanks @openperf and @vincentkoc. +- fix(logging): add redaction patterns for Tencent Cloud, Alibaba Cloud, HuggingFace and Replicate API keys (#58162). Thanks @gavyngong ## 2026.4.29 diff --git a/src/logging/redact.test.ts b/src/logging/redact.test.ts index d47109bfd7b..d64934f776b 100644 --- a/src/logging/redact.test.ts +++ b/src/logging/redact.test.ts @@ -223,6 +223,51 @@ describe("redactSensitiveText", () => { expect(output).toContain("OPENAI_API_KEY=sk-123…cdef"); }); + it("masks Tencent Cloud SecretId (AKID prefix, uppercase-only)", () => { + const input = "SecretId is AKIDZ8EXAMPLEFAKE01KEY99TEST"; + const output = redactSensitiveText(input, { + mode: "tools", + patterns: defaults, + }); + expect(output).toBe("SecretId is AKIDZ8…TEST"); + }); + + it("masks Tencent Cloud SecretId with mixed-case characters", () => { + const input = "AKIDz8exampleFake01Key99Test"; + const output = redactSensitiveText(input, { + mode: "tools", + patterns: defaults, + }); + expect(output).toBe("AKIDz8…Test"); + }); + + it("masks Alibaba Cloud AccessKey ID (LTAI prefix)", () => { + const input = "AccessKeyId=LTAI5tExampleFakeKeyXyz9"; + const output = redactSensitiveText(input, { + mode: "tools", + patterns: defaults, + }); + expect(output).toBe("AccessKeyId=LTAI5t…Xyz9"); + }); + + it("masks HuggingFace tokens (hf_ prefix)", () => { + const input = "hf_ABCDEFghijklmnopqrstuv"; + const output = redactSensitiveText(input, { + mode: "tools", + patterns: defaults, + }); + expect(output).toBe("hf_ABC…stuv"); + }); + + it("masks Replicate tokens (r8_ prefix)", () => { + const input = "r8_ABCDEFghijklmnopqrstuv"; + const output = redactSensitiveText(input, { + mode: "tools", + patterns: defaults, + }); + expect(output).toBe("r8_ABC…stuv"); + }); + it("skips redaction when mode is off", () => { const input = "OPENAI_API_KEY=sk-1234567890abcdef"; const output = redactSensitiveText(input, { diff --git a/src/logging/redact.ts b/src/logging/redact.ts index dcb935c6d8c..59d15ac70ab 100644 --- a/src/logging/redact.ts +++ b/src/logging/redact.ts @@ -39,6 +39,11 @@ const DEFAULT_REDACT_PATTERNS: string[] = [ String.raw`\b(AIza[0-9A-Za-z\-_]{20,})\b`, String.raw`\b(pplx-[A-Za-z0-9_-]{10,})\b`, String.raw`\b(npm_[A-Za-z0-9]{10,})\b`, + // Additional access-key and token-style prefixes. + String.raw`\b(AKID[A-Za-z0-9]{10,})\b`, + String.raw`\b(LTAI[A-Za-z0-9]{10,})\b`, + String.raw`\b(hf_[A-Za-z0-9]{10,})\b`, + String.raw`\b(r8_[A-Za-z0-9]{10,})\b`, // Telegram Bot API URLs embed the token as `/bot/...` (no word-boundary before digits). String.raw`\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b`, String.raw`\b(\d{6,}:[A-Za-z0-9_-]{20,})\b`,