Skip to content

tools: add ssrfPolicy for web_fetch (TUN/proxy fake-IP support)#44609

Open
zhouhe-xydt wants to merge 2 commits intoopenclaw:mainfrom
zhouhe-xydt:feat/web-fetch-ssrf-policy
Open

tools: add ssrfPolicy for web_fetch (TUN/proxy fake-IP support)#44609
zhouhe-xydt wants to merge 2 commits intoopenclaw:mainfrom
zhouhe-xydt:feat/web-fetch-ssrf-policy

Conversation

@zhouhe-xydt
Copy link
Copy Markdown
Contributor

Add ssrfPolicy for web_fetch (TUN/proxy fake-IP support)

Fixes #44527

Problem

web_fetch fails under TUN-mode proxies (e.g. Clash Verge) because:

  • TUN mode hijacks DNS and returns fake-IPs (private ranges like 198.18.x.x, 10.x.x.x)
  • web_fetch SSRF checks block private/internal IPs
  • All requests are rejected with: Blocked: resolves to private/internal/special-use IP address

Solution

Add tools.web.fetch.ssrfPolicy so operators can opt in to allowing private-network resolution when using TUN/proxy setups.

Changes

  • Config schema: Add tools.web.fetch.ssrfPolicy with dangerouslyAllowPrivateNetwork, allowPrivateNetwork (legacy), allowedHostnames, hostnameAllowlist, and allowRfc2544BenchmarkRange
  • web-fetch: Read ssrfPolicy from config and pass it to fetchWithWebToolsNetworkGuard
  • Docs: Update docs/tools/web.md, docs/gateway/configuration-reference.md, and docs/gateway/security/index.md
  • Tests: Add a test for ssrfPolicy.dangerouslyAllowPrivateNetwork: true allowing private IPs

Usage

{
  "tools": {
    "web": {
      "fetch": {
        "ssrfPolicy": {
          "dangerouslyAllowPrivateNetwork": true
        }
      }
    }
  }
}

Design notes

  • Default remains strict (dangerouslyAllowPrivateNetwork: false)
  • Operator opt-in only; matches SECURITY.md break-glass model
  • Mirrors browser.ssrfPolicy for consistency

@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation gateway Gateway runtime agents Agent runtime and tooling size: S labels Mar 13, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 13, 2026

Greptile Summary

This PR adds a tools.web.fetch.ssrfPolicy configuration option to web_fetch, mirroring the existing browser.ssrfPolicy and enabling operators using TUN-mode proxies (e.g. Clash Verge) that return fake private IPs to opt-in to allowing private-network resolution. The default remains strict, and enabling the feature requires an explicit dangerouslyAllowPrivateNetwork: true flag, consistent with the project's break-glass security model.

Key changes:

  • New ssrfPolicy field in ToolsConfig, Zod runtime schema, help, and labels — all consistent with the existing browser.ssrfPolicy shape.
  • resolveFetchSsrFPolicy() maps config to an SsrFPolicy and passes it as policy to fetchWithWebToolsNetworkGuard; because fetchWithSsrFGuard re-runs resolvePinnedHostnameWithPolicy at every redirect hop, the policy is enforced end-to-end including through redirects.
  • The new test also adds a resolvePinnedHostnameWithPolicy spy to beforeEach, which corrects a pre-existing gap where the DNS mock wasn't actually intercepting calls from fetchWithSsrFGuard (which calls resolvePinnedHostnameWithPolicy directly, not resolvePinnedHostname).
  • allowRfc2544BenchmarkRange is present in the type and Zod schema but has no schema.help.ts / schema.labels.ts entry — this matches the identical omission in browser.ssrfPolicy and so is intentional/consistent, and the help-parity quality test will still pass.

Confidence Score: 4/5

  • Safe to merge; opt-in only, default remains strict, policy is enforced at every redirect hop, and no regression risk to existing behaviour.
  • The implementation is clean and self-contained, directly mirrors the existing browser.ssrfPolicy pattern, and the SSRF policy is propagated correctly through the full redirect chain in fetchWithSsrFGuard. The new test adds useful coverage and incidentally fixes a pre-existing DNS-mock gap. One point is held back because the test only covers dangerouslyAllowPrivateNetwork; allowedHostnames and hostnameAllowlist integration paths lack dedicated tests.
  • No files require special attention; all changes are low-risk additions with no modification of existing logic.

Last reviewed commit: 41025c7

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 41025c7307

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

cacheTtlMs: resolveCacheTtlMs(fetch?.cacheTtlMinutes, DEFAULT_CACHE_TTL_MINUTES),
userAgent,
readabilityEnabled,
ssrfPolicy: resolveFetchSsrFPolicy(fetch),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include SSRF policy in web_fetch cache key

This new ssrfPolicy input changes whether private-network targets are fetchable, but runWebFetch still caches only by URL/extract mode/maxChars and returns cached content before any SSRF check. In a mixed-policy process (for example, one agent/config with dangerouslyAllowPrivateNetwork: true and another with strict defaults), a permissive request can populate cache for a private target and a later strict request will receive that cached payload instead of being blocked until TTL expiry.

Useful? React with 👍 / 👎.

@Takhoffman Takhoffman requested a review from a team as a code owner March 24, 2026 20:16
@chouzz
Copy link
Copy Markdown

chouzz commented Apr 1, 2026

This not only affects the web_fetch tool, but also affects Discord connections. After the OpenCLAW gateway restart, it fetches the Discord server failed because of SSRF.

@SonicBotMan

This comment was marked as spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling docs Improvements or additions to documentation gateway Gateway runtime size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

web_fetch 工具缺少 ssrfPolicy 配置,TUN 模式下被阻止

3 participants