Skip to content

fix(security): block SSRF via /v1/search Firecrawl provider_options.baseUrl - #10738

Merged
diegosouzapw merged 1 commit into
release/v3.8.50from
fix/port-issue-3049-ssrf-search-baseurl
Aug 19, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.50from
fix/port-issue-3049-ssrf-search-baseurl

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

  • /v1/search allowed a client with a valid API key to override the Firecrawl provider's
    server-side fetch target via provider_options.baseUrl (or the legacy top-level baseUrl),
    with no SSRF validation.
  • Any caller could redirect the search request at an internal host (loopback, RFC1918, or a
    cloud-metadata endpoint) and read the response back through the normal search result shape.

Root cause

buildFirecrawlSearchRequest() (open-sse/handlers/search/firecrawlSearch.ts) used the
client-controlled baseUrl override verbatim to build the outbound fetch URL — no SSRF guard
was applied before the fetch. Other search providers (jinaSearch, perplexitySearch) were
checked and do not accept a client-controlled baseUrl, so only Firecrawl needed the guard.

Fix

Validate the override with the project's existing parseAndValidatePublicUrl outbound URL guard
(@/shared/network/outboundUrlGuard) before it is used to build the fetch target — same guard
already used elsewhere in the codebase (webhook/provider-validation SSRF guards).

Attribution

Thanks to @zmf963 for the original report.

Test plan

  • New regression test: tests/unit/firecrawl-search-ssrf-guard.test.ts — rejects loopback,
    RFC1918, and cloud-metadata targets via both provider_options.baseUrl and legacy
    top-level baseUrl; confirms the default and an explicit public https override still work.
    node --import tsx/esm --test tests/unit/firecrawl-search-ssrf-guard.test.ts → 10/10 pass.
  • npx eslint open-sse/handlers/search/firecrawlSearch.ts tests/unit/firecrawl-search-ssrf-guard.test.ts → clean.

⚠️ base-red inherited: #9985

…aseUrl

The client-controlled provider_options.baseUrl (and legacy top-level
baseUrl) override was used verbatim to build the server-side fetch
target in buildFirecrawlSearchRequest(), with no SSRF validation. A
caller with a valid API key could redirect the search request at an
internal host (loopback, RFC1918, or a cloud-metadata endpoint) and
read the response back through the normal search result shape.

Validate the override with the existing outboundUrlGuard
(parseAndValidatePublicUrl) before it is used to build the fetch URL.
jinaSearch and perplexitySearch were checked and do not accept a
client-controlled baseUrl, so only firecrawlSearch needed the guard.

Reported-by: zmf963
@diegosouzapw
diegosouzapw merged commit c980456 into release/v3.8.50 Aug 19, 2026
11 checks passed
@diegosouzapw
diegosouzapw deleted the fix/port-issue-3049-ssrf-search-baseurl branch August 19, 2026 15:10
giauphan pushed a commit to giauphan/OmniRoute that referenced this pull request Aug 20, 2026
…aseUrl (diegosouzapw#10738)

The client-controlled provider_options.baseUrl (and legacy top-level
baseUrl) override was used verbatim to build the server-side fetch
target in buildFirecrawlSearchRequest(), with no SSRF validation. A
caller with a valid API key could redirect the search request at an
internal host (loopback, RFC1918, or a cloud-metadata endpoint) and
read the response back through the normal search result shape.

Validate the override with the existing outboundUrlGuard
(parseAndValidatePublicUrl) before it is used to build the fetch URL.
jinaSearch and perplexitySearch were checked and do not accept a
client-controlled baseUrl, so only firecrawlSearch needed the guard.

Reported-by: zmf963

Co-authored-by: Markus Hartung <mail@hartmark.se>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…aseUrl (diegosouzapw#10738)

The client-controlled provider_options.baseUrl (and legacy top-level
baseUrl) override was used verbatim to build the server-side fetch
target in buildFirecrawlSearchRequest(), with no SSRF validation. A
caller with a valid API key could redirect the search request at an
internal host (loopback, RFC1918, or a cloud-metadata endpoint) and
read the response back through the normal search result shape.

Validate the override with the existing outboundUrlGuard
(parseAndValidatePublicUrl) before it is used to build the fetch URL.
jinaSearch and perplexitySearch were checked and do not accept a
client-controlled baseUrl, so only firecrawlSearch needed the guard.

Reported-by: zmf963

Co-authored-by: Markus Hartung <mail@hartmark.se>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants