diff --git a/extensions/browser/src/browser/navigation-guard.test.ts b/extensions/browser/src/browser/navigation-guard.test.ts index 26e6e147159..34b2e0f1890 100644 --- a/extensions/browser/src/browser/navigation-guard.test.ts +++ b/extensions/browser/src/browser/navigation-guard.test.ts @@ -128,6 +128,18 @@ describe("browser navigation guard", () => { expect(lookupFn).not.toHaveBeenCalled(); }); + it("allows hostname navigation when the default strict policy object is present", async () => { + const lookupFn = createLookupFn("93.184.216.34"); + await expect( + assertBrowserNavigationAllowed({ + url: "https://example.com", + lookupFn, + ssrfPolicy: {}, + }), + ).resolves.toBeUndefined(); + expect(lookupFn).toHaveBeenCalledWith("example.com", { all: true }); + }); + it("allows explicitly allowed hostnames in strict mode", async () => { const lookupFn = createLookupFn("93.184.216.34"); await expect( @@ -300,8 +312,11 @@ describe("browser navigation guard", () => { ).resolves.toBeUndefined(); }); - it("treats default browser SSRF mode as requiring redirect-hop inspection", () => { - expect(requiresInspectableBrowserNavigationRedirects()).toBe(true); + it("requires redirect-hop inspection only in explicit strict mode", () => { + expect(requiresInspectableBrowserNavigationRedirects()).toBe(false); + expect( + requiresInspectableBrowserNavigationRedirects({ dangerouslyAllowPrivateNetwork: false }), + ).toBe(true); expect(requiresInspectableBrowserNavigationRedirects({ allowPrivateNetwork: true })).toBe( false, ); diff --git a/extensions/browser/src/browser/navigation-guard.ts b/extensions/browser/src/browser/navigation-guard.ts index 7005b1c18bd..5367c37fb6f 100644 --- a/extensions/browser/src/browser/navigation-guard.ts +++ b/extensions/browser/src/browser/navigation-guard.ts @@ -43,7 +43,7 @@ export function withBrowserNavigationPolicy( } export function requiresInspectableBrowserNavigationRedirects(ssrfPolicy?: SsrFPolicy): boolean { - return !isPrivateNetworkAllowedByPolicy(ssrfPolicy); + return ssrfPolicy?.dangerouslyAllowPrivateNetwork === false; } export function requiresInspectableBrowserNavigationRedirectsForUrl( @@ -122,6 +122,7 @@ export async function assertBrowserNavigationAllowed( // the same address that passed policy checks. if ( opts.ssrfPolicy && + opts.ssrfPolicy.dangerouslyAllowPrivateNetwork === false && !isPrivateNetworkAllowedByPolicy(opts.ssrfPolicy) && !isIpLiteralHostname(parsed.hostname) && !isExplicitlyAllowedBrowserHostname(parsed.hostname, opts.ssrfPolicy) diff --git a/extensions/browser/src/browser/routes/tabs.attach-only.test.ts b/extensions/browser/src/browser/routes/tabs.attach-only.test.ts index dcb4201e33b..73f7fb31a40 100644 --- a/extensions/browser/src/browser/routes/tabs.attach-only.test.ts +++ b/extensions/browser/src/browser/routes/tabs.attach-only.test.ts @@ -42,7 +42,7 @@ describe("browser tab routes attachOnly loopback profiles", () => { { id: "PAGE-1", title: "WordPress", - url: "https://example.test/wp-login.php", + url: "https://example.com/wp-login.php", webSocketDebuggerUrl: "ws://127.0.0.1:9222/devtools/page/PAGE-1", type: "page", }, @@ -73,7 +73,7 @@ describe("browser tab routes attachOnly loopback profiles", () => { { targetId: "PAGE-1", title: "WordPress", - url: "", + url: "https://example.com/wp-login.php", wsUrl: "ws://127.0.0.1:9222/devtools/page/PAGE-1", type: "page", }, diff --git a/extensions/browser/src/browser/server-context.remote-profile-tab-ops.fallback.test.ts b/extensions/browser/src/browser/server-context.remote-profile-tab-ops.fallback.test.ts index 7f30849c820..9de51a1a660 100644 --- a/extensions/browser/src/browser/server-context.remote-profile-tab-ops.fallback.test.ts +++ b/extensions/browser/src/browser/server-context.remote-profile-tab-ops.fallback.test.ts @@ -80,7 +80,7 @@ describe("browser remote profile fallback and attachOnly behavior", () => { it("fails closed for remote tab opens in strict mode without Playwright", async () => { vi.spyOn(deps.pwAiModule, "getPwAiModule").mockResolvedValue(null); const { state, remote, fetchMock } = deps.createRemoteRouteHarness(); - state.resolved.ssrfPolicy = {}; + state.resolved.ssrfPolicy = { dangerouslyAllowPrivateNetwork: false }; await expect(remote.openTab("https://example.com")).rejects.toBeInstanceOf( deps.InvalidBrowserNavigationUrlError,