From faebf6de5f1f6e4c78c6281ffb175eea21821d95 Mon Sep 17 00:00:00 2001 From: santosraju99-hub Date: Sun, 30 Aug 2026 12:37:18 +0530 Subject: [PATCH] fix(shared): block cloud-metadata hosts under default remote-image guard (#11755) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Boarded in a combined worktree: typecheck:core, check:dashboard-typecheck, check:file-size, check:changelog-integrity, check:complexity, check:cognitive-complexity, check:cycles, check-deps all green; 10/10 focused tests pass. Real SSRF gap confirmed — the default "block-metadata" guard mode fell through to the unchecked parseOutboundUrl() while 3 other call sites of the same guard mode already routed through parseAndValidateNonMetadataUrl(). Good catch that the existing test suite only ever exercised "public-only" explicitly. Retargeted from the stale release/v3.8.50 base to release/v3.8.51. Thanks for closing a real cloud-metadata SSRF exposure. --- src/shared/network/remoteImageFetch.ts | 5 ++- tests/unit/remote-image-fetch.test.ts | 49 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/shared/network/remoteImageFetch.ts b/src/shared/network/remoteImageFetch.ts index 2e8fc130b1..2f982a0bd9 100644 --- a/src/shared/network/remoteImageFetch.ts +++ b/src/shared/network/remoteImageFetch.ts @@ -4,6 +4,7 @@ import { Agent, fetch as undiciFetch } from "undici"; import { type OutboundUrlGuardMode, isPrivateHost, + parseAndValidateNonMetadataUrl, parseAndValidatePublicUrl, parseOutboundUrl, } from "@/shared/network/outboundUrlGuard"; @@ -51,7 +52,9 @@ export type RemoteMediaFetchOptions = RemoteImageFetchOptions; export type RemoteMediaFetchResult = RemoteImageFetchResult; function validateRemoteImageUrl(input: string | URL, guard: OutboundUrlGuardMode) { - return guard === "public-only" ? parseAndValidatePublicUrl(input) : parseOutboundUrl(input); + if (guard === "public-only") return parseAndValidatePublicUrl(input); + if (guard === "block-metadata") return parseAndValidateNonMetadataUrl(input); + return parseOutboundUrl(input); } function requireHttps(url: URL, enabled: boolean): URL { diff --git a/tests/unit/remote-image-fetch.test.ts b/tests/unit/remote-image-fetch.test.ts index 80ff9e3e7c..8014397165 100644 --- a/tests/unit/remote-image-fetch.test.ts +++ b/tests/unit/remote-image-fetch.test.ts @@ -56,3 +56,52 @@ test("fetchRemoteImage blocks redirects to private image hosts", async () => { /Blocked private or local provider URL/ ); }); + +// The default guard mode (no `guard` option passed, matching production callers that rely on +// `getProviderOutboundGuard()`'s local-first default) is "block-metadata". Every other test in +// this file passes `guard: "public-only"` explicitly, which never exercised this branch — the +// gap that let `validateRemoteImageUrl()`'s fall-through to the unchecked `parseOutboundUrl()` +// for cloud-metadata hosts go undetected. +test("fetchRemoteImage blocks cloud-metadata hosts under the default block-metadata guard", async () => { + let called = false; + + await assert.rejects( + () => + fetchRemoteImage("http://169.254.169.254/latest/meta-data", { + fetchImpl: async () => { + called = true; + return new Response("unexpected"); + }, + }), + /Blocked cloud-metadata endpoint/ + ); + + assert.equal(called, false); +}); + +test("fetchRemoteImage allows private/LAN image hosts under the default block-metadata guard", async () => { + const result = await fetchRemoteImage("http://192.168.1.50:8080/local.png", { + fetchImpl: async () => + new Response(new Uint8Array([1, 2, 3]), { + status: 200, + headers: { "content-type": "image/png" }, + }), + }); + + assert.equal(result.buffer.toString("base64"), "AQID"); +}); + +test("fetchRemoteImage blocks redirects to cloud-metadata hosts under the default block-metadata guard", async () => { + await assert.rejects( + () => + fetchRemoteImage("https://cdn.example.com/redirect.png", { + fetchImpl: async () => + new Response(null, { + status: 302, + headers: { location: "http://169.254.169.254/latest/meta-data" }, + }), + lookup: publicLookup, + }), + /Blocked cloud-metadata endpoint/ + ); +});