From e8a158e4f5096e5200dc47c8d5d5148770ace234 Mon Sep 17 00:00:00 2001 From: zengLingbiao Date: Sun, 2 Aug 2026 07:25:32 +0800 Subject: [PATCH] fix(signal): cancel unread body when declared archive length exceeds cap (#117665) --- .../signal/src/install-signal-cli.test.ts | 19 +++++++++++++++++++ extensions/signal/src/install-signal-cli.ts | 1 + 2 files changed, 20 insertions(+) diff --git a/extensions/signal/src/install-signal-cli.test.ts b/extensions/signal/src/install-signal-cli.test.ts index 5521f84f2725..00a2292eacd7 100644 --- a/extensions/signal/src/install-signal-cli.test.ts +++ b/extensions/signal/src/install-signal-cli.test.ts @@ -291,6 +291,25 @@ describe("downloadToFile", () => { expect(cancel).toHaveBeenCalledOnce(); }); + it("cancels the response body when the declared length exceeds the download cap", async () => { + const response = new Response("archive", { + status: 200, + headers: { "content-length": "12" }, + }); + const cancel = vi.spyOn(response.body!, "cancel").mockRejectedValueOnce(new Error("closed")); + fetchWithSsrFGuardMock.mockResolvedValue({ response, release: vi.fn() }); + + await withTempFile(async (filePath) => { + await expect( + downloadToFile("https://example.com/signal-cli.tgz", filePath, 5, 8), + ).rejects.toThrow("declared 12"); + + await expectPathMissing(filePath); + }); + + expect(cancel).toHaveBeenCalledOnce(); + }); + it("downloads through the SSRF guard with an explicit timeout", async () => { const fetchResult = okDownloadResponse("archive"); fetchWithSsrFGuardMock.mockResolvedValue(fetchResult); diff --git a/extensions/signal/src/install-signal-cli.ts b/extensions/signal/src/install-signal-cli.ts index 26ecf050a536..07fc5d7404a9 100644 --- a/extensions/signal/src/install-signal-cli.ts +++ b/extensions/signal/src/install-signal-cli.ts @@ -194,6 +194,7 @@ export async function downloadToFile( ? Number(trimmedLength) : Number.NaN; if (Number.isFinite(declaredLength) && declaredLength > maxBytes) { + await cancelUnusedResponseBody(response); throw new Error( `signal-cli archive exceeds the ${maxBytes}-byte download cap (declared ${declaredLength}).`, );