fix(web-search): restrict private network guard

This commit is contained in:
Peter Steinberger
2026-05-02 06:39:40 +01:00
parent e052bdcfb6
commit 1771160d2c
12 changed files with 143 additions and 20 deletions

View File

@@ -7,8 +7,8 @@ import {
readResponseText,
resolveCacheTtlMs,
truncateText,
withSelfHostedWebToolsEndpoint,
withStrictWebToolsEndpoint,
withTrustedWebToolsEndpoint,
writeCache,
} from "openclaw/plugin-sdk/provider-web-fetch";
import { normalizeSecretInput } from "openclaw/plugin-sdk/secret-input";
@@ -45,7 +45,7 @@ const FIRECRAWL_SELF_HOSTED_PRIVATE_ERROR =
const FIRECRAWL_HTTP_PRIVATE_ERROR =
"Firecrawl HTTP baseUrl must target a private or internal self-hosted endpoint. Use https:// for public hosts.";
type FirecrawlEndpointMode = "strict" | "trusted";
type FirecrawlEndpointMode = "selfHosted" | "strict";
type FirecrawlResolvedEndpoint = {
url: string;
mode: FirecrawlEndpointMode;
@@ -124,7 +124,7 @@ async function validateFirecrawlBaseUrl(
const isPrivateTarget = await firecrawlEndpointTargetsPrivateNetwork(url, lookupFn);
if (isPrivateTarget) {
return "trusted";
return "selfHosted";
}
if (url.protocol === "http:") {
throw new Error(FIRECRAWL_HTTP_PRIVATE_ERROR);
@@ -161,7 +161,7 @@ async function postFirecrawlJson<T>(
const apiKey = normalizeSecretInput(params.apiKey);
const mode = params.mode ?? (await validateFirecrawlBaseUrl(params.url));
const withEndpoint =
mode === "trusted" ? withTrustedWebToolsEndpoint : withStrictWebToolsEndpoint;
mode === "selfHosted" ? withSelfHostedWebToolsEndpoint : withStrictWebToolsEndpoint;
return await withEndpoint(
{
url: params.url,

View File

@@ -616,7 +616,7 @@ describe("firecrawl tools", () => {
firecrawlClientTesting.resolveEndpoint("http://127.0.0.1:8787", "/v2/scrape"),
).resolves.toEqual({
url: "http://127.0.0.1:8787/v2/scrape",
mode: "trusted",
mode: "selfHosted",
});
await expect(
firecrawlClientTesting.resolveEndpoint(
@@ -625,7 +625,7 @@ describe("firecrawl tools", () => {
),
).resolves.toEqual({
url: "https://host.openshell.internal:444/v2/search",
mode: "trusted",
mode: "selfHosted",
});
await expect(
firecrawlClientTesting.resolveEndpoint("http://api.firecrawl.dev", "/v2/scrape"),
@@ -638,7 +638,7 @@ describe("firecrawl tools", () => {
).rejects.toThrow("Firecrawl baseUrl must use http:// or https://.");
});
it("routes private self-hosted Firecrawl endpoints through the trusted fetch guard", async () => {
it("routes private self-hosted Firecrawl endpoints through the self-hosted fetch guard", async () => {
ssrfMock?.mockRestore();
ssrfMock = mockPinnedHostnameResolution(["127.0.0.1"]);
const fetchSpy = vi.fn(