Skip to content

[Bug] web_fetch fails for every hostname under a TUN fake-IP proxy: upstream SSRF guard rejects 198.18.0.0/15, bundled build has no proxy fallback #1667

Description

@Astro-Han

What happened?

On this machine web_fetch fails for every hostname:

ToolCallError: URL hostname "support.optimizely.com" resolves to a non-public IP address

web_search still works, so only the local fetch provider is affected. The cause is the SSRF pre-check in the bundled @deepseek-ai/dsh-web-fetch-http@0.1.5-rc.1: the system resolver returns an address from the local proxy's fake-IP pool (198.18.0.0/15), the guard classifies it as non-public, and the whole answer set is rejected with WEB_BLOCKED_URL.

Root cause is upstream and already reported there (discussion #5202, duplicates #6112 / #6457 / #6737). Filing it here because the failure ships inside PawWork, and the copy that actually runs is the one in the app bundle.

Which area seems affected?

Model harness, prompts, tools, or session mechanics

How much does this affect you?

Breaks an important workflow (there is a workaround)

Steps to reproduce

  1. Run on macOS behind a TUN/fake-IP proxy. Here: Clash Verge Rev, TUN mode, fake-ip-range: 198.18.0.1/16, mixed-port: 7897.
  2. Confirm the resolver: dig www.barra.ai → 198.18.1.51; github.com → 198.18.0.31; even www.baidu.com → 198.18.1.54 (in this setup every host lands in the fake-IP pool).
  3. Ask PawWork to fetch any https URL, e.g. https://support.optimizely.com/hc/en-us/articles/4410284003341-Statistical-significance.
  4. ToolCallError: URL hostname "…" resolves to a non-public IP address.

curl to the same URLs returns 200, both direct and through http://127.0.0.1:7897. The network path is fine; only the guard rejects.

What did you expect to happen?

web_fetch returns the page. This machine already has the system HTTP/HTTPS proxy configured (scutil --proxy reports HTTP, HTTPS and SOCKS all at 127.0.0.1:7897), so the fetch should be able to use it without manual environment setup.

PawWork version

2026.9.8

OS version

macOS 27.0 (26A428), arm64

Can you reproduce it again?

Yes, every time

Diagnostics

  • Bundled package: Contents/Resources/app/node_modules/@deepseek-ai/dsh-web-fetch-http 0.1.5-rc.1. <DSH_HOME>/profiles/node_modules/@deepseek-ai/dsh-web-fetch-http is a symlink into the app bundle, so a PawWork patch is what reaches the runtime.
  • Throwing line: lib/index.js:70 — if (!isPublicIpAddress(entry.address)) throw new WebError(...). isPublicIpAddress is ipaddr.js range() === "unicast", and 198.18.1.47 classifies as reserved.
  • Upgrade does not fix it: 0.1.5-rc.2 and 0.1.6-alpha.1 are the newest published versions and their lib/index.js files are byte-identical to each other (diff → 0 lines), with the same check.
  • The proxy escape hatch is not automatic: proxyRouteFor reads http_proxy / https_proxy / no_proxy from the environment only, and macOS system proxy settings are not read. With no HTTPS_PROXY set, the fetch takes the direct path, resolves through the fake-IP resolver, and throws. Upstream comments confirm a proxied hop skips resolution and pinning by design (provider.ts:123-125, asserted by tests/proxy.spec.ts:75-86).

Suggested fix (PawWork side, follows the existing patch pattern)

pnpm-workspace.yaml already patches two DSH packages (dsh-client-connection, dsh-llm-pi-ai). Add a third for dsh-web-fetch-http@0.1.5-rc.1:

  1. When HTTPS_PROXY/HTTP_PROXY are absent, fall back to the platform proxy (macOS scutil --proxy), which makes the documented escape hatch the default instead of something the user has to discover.
  2. Treat the known fake-IP ranges (198.18.0.0/15) as "local DNS is owned by a proxy" and route that hop through the proxy, instead of pinning an address that cannot be connected to.

SSRF posture is unchanged: RFC1918/loopback/cloud-metadata answers and IP literals stay rejected.

Workaround until then

Set both HTTP_PROXY and HTTPS_PROXY to the local mixed port (http://127.0.0.1:7897) in the environment the DSH sidecar starts with. HTTPS_PROXY alone is not enough — the fallback is asymmetric, so plain http:// URLs still fail (upstream comment, 2026-09-15).

Not urgent: there is a workaround, and the upstream discussion is already tracking the root cause.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium prioritybugSomething isn't workingupstreamTracked upstream or vendor behavior

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions