fix(withings): cap WithingsApiError message at 1024 chars

A misbehaving Withings upstream that returns a multi-MB error body
could bloat any AuditLog.details row that captured the thrown
message. Apply the cap inside the constructor so every downstream
audit, notification, and pg-boss retry path inherits the bound
without touching call sites.

Closes the v1.4.42 L-1 carry-over. A regression test asserts the
1024-char cap for a 4000-char upstreamError while preserving the
"Withings <verb> error: <status>" prefix the legacy regex parser
depends on.
This commit is contained in:
Marc-André Bombeck committed 2026-05-21 21:44:30 +02:00
1 parent b70cdcae48
commit 921d31b8fe
2 files changed
+24 -1

No files matched your search

@@ -174,6 +174,23 @@ describe("WithingsApiError", () => {
});
expect(err.message).toBe("Withings subscribe error: 293");
});
// v1.4.43 W3-SECURITY (H-2, v1.4.42 L-1 carry-over) — the constructor
// caps the message at 1024 chars so a misbehaving upstream cannot
// bloat an `AuditLog.details` row through any downstream wrapper.
it("caps the message at 1024 chars when upstreamError is unbounded", () => {
const huge = "x".repeat(4000);
const err = new WithingsApiError({
verb: "measure",
classification: "transient",
withingsStatus: 503,
reason: "withings_503",
upstreamError: huge,
});
expect(err.message.length).toBe(1024);
// Prefix preserved so the legacy regex parser still matches.
expect(err.message.startsWith("Withings measure error: 503 - ")).toBe(true);
});
});
describe("classifyError", () => {
+7 -1
View File
@@ -246,7 +246,13 @@ export class WithingsApiError extends Error {
const statusLabel =
typeof opts.withingsStatus === "number" ? opts.withingsStatus : "?";
const errSegment = opts.upstreamError ? ` - ${opts.upstreamError}` : "";
super(`Withings ${opts.verb} error: ${statusLabel}${errSegment}`);
// v1.4.43 W3-SECURITY (H-2, v1.4.42 L-1 carry-over): cap the
// message at 1024 chars in the constructor so every downstream
// audit / notification path inherits the bound. A misbehaving
// upstream that returns a multi-MB error body must not be able to
// bloat an `AuditLog.details` row.
const raw = `Withings ${opts.verb} error: ${statusLabel}${errSegment}`;
super(raw.slice(0, 1024));
this.name = "WithingsApiError";
this.verb = opts.verb;
this.classification = opts.classification;