mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:10:43 +00:00
fix(browser): auto-allowlist configured CDP hostnames in SSRF policy
This commit is contained in:
@@ -343,6 +343,52 @@ describe("browser config", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("auto-allowlists hostnames from user-configured profile cdpUrls", () => {
|
||||
const resolved = resolveBrowserConfig({
|
||||
profiles: {
|
||||
remote: {
|
||||
color: "#123456",
|
||||
cdpUrl: "http://172.29.128.1:9223",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(resolved.ssrfPolicy).toEqual({
|
||||
allowedHostnames: ["172.29.128.1"],
|
||||
});
|
||||
});
|
||||
|
||||
it("merges configured profile cdpUrl hostnames with existing ssrfPolicy allowedHostnames", () => {
|
||||
const resolved = resolveBrowserConfig({
|
||||
ssrfPolicy: {
|
||||
allowedHostnames: ["metadata.internal"],
|
||||
},
|
||||
profiles: {
|
||||
remote: {
|
||||
color: "#123456",
|
||||
cdpUrl: "http://172.29.128.1:9223",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(resolved.ssrfPolicy?.allowedHostnames?.toSorted()).toEqual(
|
||||
["172.29.128.1", "metadata.internal"].toSorted(),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not duplicate hostnames already in allowedHostnames", () => {
|
||||
const resolved = resolveBrowserConfig({
|
||||
ssrfPolicy: {
|
||||
allowedHostnames: ["172.29.128.1"],
|
||||
},
|
||||
profiles: {
|
||||
remote: {
|
||||
color: "#123456",
|
||||
cdpUrl: "http://172.29.128.1:9223",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(resolved.ssrfPolicy?.allowedHostnames).toEqual(["172.29.128.1"]);
|
||||
});
|
||||
|
||||
it("resolves existing-session profiles without cdpPort or cdpUrl", () => {
|
||||
const resolved = resolveBrowserConfig({
|
||||
profiles: {
|
||||
|
||||
@@ -126,11 +126,27 @@ function resolveCdpPortRangeStart(
|
||||
|
||||
const normalizeStringList = normalizeOptionalTrimmedStringList;
|
||||
|
||||
function resolveBrowserSsrFPolicy(cfg: BrowserConfig | undefined): SsrFPolicy | undefined {
|
||||
function mergeAllowedHostnames(
|
||||
base: string[] | undefined,
|
||||
extra: readonly string[],
|
||||
): string[] | undefined {
|
||||
if (extra.length === 0) {
|
||||
return base;
|
||||
}
|
||||
return Array.from(new Set([...(base ?? []), ...extra]));
|
||||
}
|
||||
|
||||
function resolveBrowserSsrFPolicy(
|
||||
cfg: BrowserConfig | undefined,
|
||||
extraAllowedHostnames: readonly string[] = [],
|
||||
): SsrFPolicy | undefined {
|
||||
const rawPolicy = cfg?.ssrfPolicy as BrowserSsrFPolicyCompat | undefined;
|
||||
const allowPrivateNetwork = rawPolicy?.allowPrivateNetwork;
|
||||
const dangerouslyAllowPrivateNetwork = rawPolicy?.dangerouslyAllowPrivateNetwork;
|
||||
const allowedHostnames = normalizeStringList(rawPolicy?.allowedHostnames);
|
||||
const allowedHostnames = mergeAllowedHostnames(
|
||||
normalizeStringList(rawPolicy?.allowedHostnames),
|
||||
extraAllowedHostnames,
|
||||
);
|
||||
const hostnameAllowlist = normalizeStringList(rawPolicy?.hostnameAllowlist);
|
||||
const hasExplicitPrivateSetting =
|
||||
allowPrivateNetwork !== undefined || dangerouslyAllowPrivateNetwork !== undefined;
|
||||
@@ -159,6 +175,30 @@ function resolveBrowserSsrFPolicy(cfg: BrowserConfig | undefined): SsrFPolicy |
|
||||
};
|
||||
}
|
||||
|
||||
function collectConfiguredCdpHostnames(cfg: BrowserConfig | undefined): string[] {
|
||||
const hostnames = new Set<string>();
|
||||
const addHostnameFromUrl = (rawUrl: string | undefined): void => {
|
||||
const trimmed = rawUrl?.trim() ?? "";
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const hostname = new URL(trimmed).hostname;
|
||||
if (hostname) {
|
||||
hostnames.add(hostname);
|
||||
}
|
||||
} catch {
|
||||
// Ignore unparseable URLs; they will be rejected elsewhere with a proper error.
|
||||
}
|
||||
};
|
||||
|
||||
addHostnameFromUrl(cfg?.cdpUrl);
|
||||
for (const profile of Object.values(cfg?.profiles ?? {})) {
|
||||
addHostnameFromUrl(profile?.cdpUrl);
|
||||
}
|
||||
return Array.from(hostnames);
|
||||
}
|
||||
|
||||
function ensureDefaultProfile(
|
||||
profiles: Record<string, BrowserProfileConfig> | undefined,
|
||||
defaultColor: string,
|
||||
@@ -293,7 +333,7 @@ export function resolveBrowserConfig(
|
||||
attachOnly,
|
||||
defaultProfile,
|
||||
profiles,
|
||||
ssrfPolicy: resolveBrowserSsrFPolicy(cfg),
|
||||
ssrfPolicy: resolveBrowserSsrFPolicy(cfg, collectConfiguredCdpHostnames(cfg)),
|
||||
extraArgs,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user