diff --git a/scripts/e2e/kitchen-sink-rpc-walk.mjs b/scripts/e2e/kitchen-sink-rpc-walk.mjs index 37190651820f..8ad3ea41c02e 100644 --- a/scripts/e2e/kitchen-sink-rpc-walk.mjs +++ b/scripts/e2e/kitchen-sink-rpc-walk.mjs @@ -980,7 +980,7 @@ export async function readBoundedResponseText(response, byteLimit, timeoutPromis const contentLength = response.headers?.get?.("content-length"); if (contentLength && /^\d+$/u.test(contentLength)) { const parsedContentLength = Number(contentLength); - if (Number.isSafeInteger(parsedContentLength) && parsedContentLength > resolvedByteLimit) { + if (!Number.isSafeInteger(parsedContentLength) || parsedContentLength > resolvedByteLimit) { await response.body?.cancel?.().catch(() => undefined); throw createFetchBodyTooLargeError(resolvedByteLimit); } diff --git a/test/scripts/kitchen-sink-rpc-walk.test.ts b/test/scripts/kitchen-sink-rpc-walk.test.ts index 17d6ec3f16d2..8b763874d374 100644 --- a/test/scripts/kitchen-sink-rpc-walk.test.ts +++ b/test/scripts/kitchen-sink-rpc-walk.test.ts @@ -1923,6 +1923,21 @@ describe("kitchen-sink RPC process sampling", () => { expect(response.text).not.toHaveBeenCalled(); }); + it("rejects unsafe decimal HTTP content lengths before reading", async () => { + const response = { + headers: new Headers({ + "content-length": "9007199254740992", + }), + text: vi.fn(async () => "not read"), + }; + + await expect(readBoundedResponseText(response, 1024)).rejects.toMatchObject({ + code: "ETOOBIG", + message: "fetch response body exceeded 1024 bytes", + }); + expect(response.text).not.toHaveBeenCalled(); + }); + it("streams HTTP probe responses with non-decimal content-length values", async () => { let readStarted = false; let canceled = false;