From a38b3bd1df65cb35454a360397bcd8970e77f810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 10 Aug 2026 00:25:56 +0200 Subject: [PATCH] Redact a warning on the way into the wide event addWarning pushed the raw string while setError, setHttp and addExternalCall all scrub through redactSecrets. A warning routinely carries an outbound error string, and for several integrations that string is the request URL with a credential in it, so a secret could reach stdout and the log store unredacted. It now scrubs on the way in like the other entry points, and a test asserts a licence-key-bearing warning is masked. --- .../__tests__/event-builder-redaction.test.ts | 12 ++++++++++++ src/lib/logging/event-builder.ts | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/lib/logging/__tests__/event-builder-redaction.test.ts b/src/lib/logging/__tests__/event-builder-redaction.test.ts index be692201b..37602c130 100644 --- a/src/lib/logging/__tests__/event-builder-redaction.test.ts +++ b/src/lib/logging/__tests__/event-builder-redaction.test.ts @@ -36,6 +36,18 @@ describe("wide-event builder — redaction at every entry point", () => { expect(emitted(b)).not.toContain("AAH-SuperSecretBotTokenValue"); }); + it("scrubs a credential that arrives through addWarning", () => { + // A warning often carries an outbound error string, and for several + // integrations that string is the request URL with a secret in it (a + // GeoLite2 download carries the licence key). It must be scrubbed on the + // way in, the same as setError / setHttp / addExternalCall. + const b = new WideEventBuilder("background"); + b.addWarning( + "geolite2 download failed: https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=SECRET_MAXMIND_KEY&suffix=tar.gz", + ); + expect(emitted(b)).not.toContain("SECRET_MAXMIND_KEY"); + }); + it("scrubs an API key that arrives through addMeta", () => { const b = new WideEventBuilder("http"); b.addMeta( diff --git a/src/lib/logging/event-builder.ts b/src/lib/logging/event-builder.ts index 7af2d2d77..13347ae3b 100644 --- a/src/lib/logging/event-builder.ts +++ b/src/lib/logging/event-builder.ts @@ -176,7 +176,11 @@ export class WideEventBuilder { addWarning(msg: string): this { this.elevateLevel("warn"); if (!this.event.warnings) this.event.warnings = []; - this.event.warnings.push(msg); + // Scrub on the way in, like setError / setHttp / addExternalCall. A warning + // often carries an outbound error string, which for several integrations is + // the request URL with a credential in it (a bot token, an OAuth code, a + // licence key). The redaction contract is the builder's, not each caller's. + this.event.warnings.push(redactSecrets(msg)); return this; }