From 5fd87a28e4b1f5688de2944dee38a26292dee8ee Mon Sep 17 00:00:00 2001 From: wahaha1223 <0668001153@xydigit.com> Date: Tue, 21 Jul 2026 12:31:08 +0800 Subject: [PATCH] fix(clawrouter): reject invalid UTF-8 usage responses (#111183) Co-authored-by: wahaha1223 <304197929+wahaha1223@users.noreply.github.com> --- extensions/clawrouter/usage.test.ts | 16 ++++++++++++++++ extensions/clawrouter/usage.ts | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/extensions/clawrouter/usage.test.ts b/extensions/clawrouter/usage.test.ts index 5cae5c6525ee..4da3c5e44e98 100644 --- a/extensions/clawrouter/usage.test.ts +++ b/extensions/clawrouter/usage.test.ts @@ -205,6 +205,22 @@ describe("ClawRouter usage", () => { expect(snapshot.billing).toEqual([{ type: "spend", amount: 0, unit: "USD" }]); }); + it("rejects usage JSON containing invalid UTF-8", async () => { + const prefix = new TextEncoder().encode( + '{"budget":{"configured":true,"windowKey":"default/test-policy/2026-', + ); + const suffix = new TextEncoder().encode('","limitMicros":1000000,"spentMicros":500000}}'); + const body = new Uint8Array([...prefix, 0xff, ...suffix]); + + await expect( + fetchClawRouterUsage({ + token: "test-token", + timeoutMs: 5000, + fetchGuard: mockFetchGuard(new Response(body)), + }), + ).rejects.toThrow(TypeError); + }); + it("cancels non-OK usage response body before throwing", async () => { let cancelled = false; const response = new Response( diff --git a/extensions/clawrouter/usage.ts b/extensions/clawrouter/usage.ts index 8c64b841f5f4..b596a4b9c04b 100644 --- a/extensions/clawrouter/usage.ts +++ b/extensions/clawrouter/usage.ts @@ -82,7 +82,9 @@ async function readClawRouterUsagePayload( onIdleTimeout: ({ chunkTimeoutMs }) => new Error(`ClawRouter usage response stalled: no data received for ${chunkTimeoutMs}ms`), }); - return JSON.parse(new TextDecoder().decode(buffer)) as ClawRouterUsagePayload; + return JSON.parse( + new TextDecoder("utf-8", { fatal: true }).decode(buffer), + ) as ClawRouterUsagePayload; } export async function fetchClawRouterUsage(params: {