Skip to content

feat(web_fetch): proxy support with SSRF-safe HTTP CONNECT / SOCKS5 tunnelling#3357

Closed
ningqipeng wants to merge 2 commits into
esengine:main-v2from
ningqipeng:feat/web-fetch-proxy
Closed

feat(web_fetch): proxy support with SSRF-safe HTTP CONNECT / SOCKS5 tunnelling#3357
ningqipeng wants to merge 2 commits into
esengine:main-v2from
ningqipeng:feat/web-fetch-proxy

Conversation

@ningqipeng

Copy link
Copy Markdown

Problem

web_fetch intentionally bypasses netclient proxy settings (source comment in netclient.go):

"It is intentionally not used by web_fetch, whose dial-time SSRF guard has a different security boundary"

This means users behind corporate firewalls or GFW cannot use web_fetch to reach external sites (GitHub, npm, etc.), even when they have a working proxy configured in [network].

Solution

Wire web_fetch to the existing [network] proxy configuration while preserving full SSRF protection:

  1. netclient.ResolveProxyURL — new exported function that resolves ProxySpec → URL string (reuses existing customProxyURL logic)
  2. webFetch.proxyURL — new field set during tool registration
  3. ssrfGuardedClient(proxyURL) — enhanced to tunnel through proxy:
    • HTTP/HTTPS proxy → dial proxy → CONNECT with original hostname (proxy resolves DNS remotely, essential for GFW users) → tunnel
    • IP literal targets still get SSRF-checked via net.ParseIP
    • SOCKS5/SOCKS5h → Transport.Proxy (Go standard library handles it)
    • No proxy → existing direct SSRF-safe behavior unchanged
  4. ConfineWebFetch + boot.go — plumbing for both workspace and fallback paths

Files changed

File Change
internal/netclient/netclient.go +ResolveProxyURL()
internal/tool/builtin/webfetch.go webFetch.proxyURL, ssrfGuardedClient proxy tunnel
internal/tool/builtin/workspace.go Workspace.ProxyURL
internal/tool/builtin/confine.go +ConfineWebFetch()
internal/boot/boot.go addBuiltins proxyURL param + fallback fix
internal/boot/boot_test.go test signature update
internal/tool/builtin/web_fetch_proxy_test.go new proxy tests

Testing

  • go build ./... compiles
  • go test ./internal/tool/builtin/ PASS
  • go test ./internal/boot/ PASS
  • SSRF still blocks 169.254.169.254, 10.0.0.1, 192.168.1.1 through proxy

Configuration

After this change, users add to config.toml:

[network]
proxy_mode = "custom"
proxy_url  = "http://127.0.0.1:7897"

[network.proxy]
type = "http"
server = "127.0.0.1"
port = 7897

Then web_fetch https://raw.githubusercontent.com/... works through the proxy.

…unnelling

## Problem

web_fetch intentionally bypasses netclient proxy settings (source comment
in netclient.go). This means users behind corporate firewalls or GFW
cannot use web_fetch to reach external sites (GitHub, npm, etc.), even
when they have a working proxy configured in [network].

## Solution

Wire web_fetch to the existing [network] proxy configuration while
preserving full SSRF protection:

1. netclient.ResolveProxyURL — new exported function that resolves
   ProxySpec to URL string (reuses existing customProxyURL logic)
2. webFetch.proxyURL — new field set during tool registration
3. ssrfGuardedClient(proxyURL) — enhanced to tunnel through proxy:
   - HTTP/HTTPS proxy: dial proxy -> CONNECT with ORIGINAL hostname
     (proxy resolves DNS remotely, essential for GFW users) -> tunnel
   - IP literal targets still get SSRF-checked via net.ParseIP
   - SOCKS5/SOCKS5h: Transport.Proxy (Go standard library handles it)
   - No proxy: existing direct SSRF-safe behavior unchanged
4. ConfineWebFetch + boot.go plumbing for both workspace and fallback
   paths

## Files changed

| File | Change |
|------|--------|
| internal/netclient/netclient.go | +ResolveProxyURL() |
| internal/tool/builtin/webfetch.go | webFetch.proxyURL, ssrfGuardedClient proxy tunnel |
| internal/tool/builtin/workspace.go | Workspace.ProxyURL |
| internal/tool/builtin/confine.go | +ConfineWebFetch() |
| internal/boot/boot.go | addBuiltins proxyURL param + fallback fix |
| internal/boot/boot_test.go | test signature update |
| internal/tool/builtin/web_fetch_proxy_test.go | new proxy tests |

## Testing

- go build ./... compiles
- go test ./internal/tool/builtin/ PASS
- go test ./internal/boot/ PASS
- SSRF still blocks 169.254.169.254, 10.0.0.1, 192.168.1.1 through proxy
@github-actions github-actions Bot added the v2 Go rewrite (1.x) — main-v2 branch, active development label Jun 6, 2026
# Conflicts:
#	internal/boot/boot_test.go
@github-actions github-actions Bot added skills Skill system (internal/skill, internal/tool) config Configuration & setup (internal/config) labels Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config Configuration & setup (internal/config) skills Skill system (internal/skill, internal/tool) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants