mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 20:00:42 +00:00
fix(browser): relax default hostname SSRF guard
This commit is contained in:
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user