Skip to content

feat(tools): add proxy support for web_fetch tool#5831

Closed
bobcyw wants to merge 4 commits intoopenclaw:mainfrom
bobcyw:feat/web-fetch-proxy
Closed

feat(tools): add proxy support for web_fetch tool#5831
bobcyw wants to merge 4 commits intoopenclaw:mainfrom
bobcyw:feat/web-fetch-proxy

Conversation

@bobcyw
Copy link

@bobcyw bobcyw commented Feb 1, 2026

Add HTTP proxy configuration option for the web_fetch tool, allowing requests to be routed through a proxy server.

Configuration example:
tools.web.fetch.proxy: "http://127.0.0.1:7890"

Greptile Overview

Greptile Summary

This PR adds a new tools.web.fetch.proxy config option and wires it through createWebFetchTool() into the fetch path, using undici’s ProxyAgent so web_fetch requests can be routed via an HTTP proxy. It also updates the config UI hints/types/runtime zod schema and adds tests intended to cover the new proxy behavior.

The main concern is that the implementation switches from the existing pinned-dispatcher SSRF protection to a raw proxy dispatcher when proxy is enabled, which changes the security model of web_fetch in a way that can allow fetching internal resources if the proxy can reach them. Additionally, the proxy agent lifecycle/closing behavior looks inconsistent with the “reused” intent, and the new tests don’t currently validate that proxy mode is actually being exercised.

Confidence Score: 2/5

  • This PR has meaningful security/behavioral risk due to proxy mode bypassing SSRF protections and should not merge as-is.
  • While the config plumbing is straightforward, enabling proxy currently skips the pinned-dispatcher SSRF defense, which is a significant behavioral change in a security-sensitive tool. There’s also likely confusion around ProxyAgent lifecycle (closed in finally despite comments about reuse), and the added tests don’t strongly validate proxy behavior, increasing the chance of regressions going unnoticed.
  • src/agents/tools/web-fetch.ts (proxy vs SSRF behavior; dispatcher lifecycle); src/agents/tools/web-tools.fetch.test.ts (strengthen assertions)

(4/5) You can add custom instructions or style guidelines for the agent here!

Context used:

  • Context from dashboard - CLAUDE.md (source)
  • Context from dashboard - AGENTS.md (source)

@openclaw-barnacle openclaw-barnacle bot added the agents Agent runtime and tooling label Feb 1, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +206 to +213
// Use proxy dispatcher if available, otherwise use pinned dispatcher for SSRF protection
let dispatcher: Dispatcher;
if (proxyDispatcher) {
dispatcher = proxyDispatcher;
} else {
const pinned = await resolvePinnedHostname(parsedUrl.hostname);
dispatcher = createPinnedDispatcher(pinned);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

[P0] Proxy support bypasses SSRF pinning

When params.proxy is set, this skips resolvePinnedHostname()/createPinnedDispatcher() entirely and uses ProxyAgent directly, which effectively disables the repo’s SSRF protection for web_fetch in proxied mode. This becomes a real security issue if proxy support is used in environments where the proxy can reach internal networks or can be influenced/controlled by an attacker.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/web-fetch.ts
Line: 206:213

Comment:
[P0] Proxy support bypasses SSRF pinning

When `params.proxy` is set, this skips `resolvePinnedHostname()`/`createPinnedDispatcher()` entirely and uses `ProxyAgent` directly, which effectively disables the repo’s SSRF protection for web_fetch in proxied mode. This becomes a real security issue if proxy support is used in environments where the proxy can reach internal networks or can be influenced/controlled by an attacker.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +184 to +191
}): Promise<{ response: Response; finalUrl: string; dispatcher: Dispatcher }> {
const signal = withTimeout(undefined, params.timeoutSeconds * 1000);
const visited = new Set<string>();
let currentUrl = params.url;
let redirectCount = 0;

// Create proxy dispatcher if configured
const proxyDispatcher = params.proxy ? new ProxyAgent(params.proxy) : null;
Copy link
Contributor

Choose a reason for hiding this comment

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

[P1] ProxyAgent lifecycle likely closed too early

fetchWithRedirects() returns { dispatcher } even when that dispatcher is proxyDispatcher, and runWebFetch() always does await closeDispatcher(dispatcher) in finally. That means the proxy dispatcher is likely closed after every request despite the comment that it’s “reused”, and it’s also never explicitly closed on the success path inside fetchWithRedirects(). This can lead to confusing behavior or resource churn depending on how undici’s ProxyAgent manages connections.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/web-fetch.ts
Line: 184:191

Comment:
[P1] ProxyAgent lifecycle likely closed too early

`fetchWithRedirects()` returns `{ dispatcher }` even when that dispatcher is `proxyDispatcher`, and `runWebFetch()` always does `await closeDispatcher(dispatcher)` in `finally`. That means the proxy dispatcher is likely closed after every request despite the comment that it’s “reused”, and it’s also never explicitly closed on the success path inside `fetchWithRedirects()`. This can lead to confusing behavior or resource churn depending on how undici’s `ProxyAgent` manages connections.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +295 to +300
it("uses proxy dispatcher when proxy is configured", async () => {
let capturedDispatcher: unknown = null;
const mockFetch = vi.fn((input: RequestInfo, init?: RequestInit) => {
capturedDispatcher = (init as { dispatcher?: unknown })?.dispatcher;
return Promise.resolve(
htmlResponse("<html><body><p>Hello via proxy</p></body></html>", requestUrl(input)),
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2] Proxy tests don't actually assert proxy behavior

Both proxy-related tests only assert that a dispatcher was passed to fetch, but they never verify it's a ProxyAgent when proxy is configured, nor that SSRF pinning was skipped/called appropriately. As written, these tests would still pass if the dispatcher wiring were wrong (e.g., always using a pinned dispatcher).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/web-tools.fetch.test.ts
Line: 295:300

Comment:
[P2] Proxy tests don't actually assert proxy behavior

Both proxy-related tests only assert that a `dispatcher` was passed to fetch, but they never verify it's a `ProxyAgent` when proxy is configured, nor that SSRF pinning was skipped/called appropriately. As written, these tests would still pass if the dispatcher wiring were wrong (e.g., always using a pinned dispatcher).

How can I resolve this? If you propose a fix, please make it concise.

@bobcyw bobcyw force-pushed the feat/web-fetch-proxy branch from 1ea6a71 to 5390624 Compare February 1, 2026 01:48
bobcyw and others added 4 commits February 1, 2026 11:46
Add HTTP proxy configuration option for the web_fetch tool, allowing
requests to be routed through a proxy server.

Configuration example:
  tools.web.fetch.proxy: "http://127.0.0.1:7890"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- P0: Add comments clarifying SSRF bypass is intentional when proxy is configured
- P1: Fix dispatcher lifecycle by tracking isProxyDispatcher flag
- P2: Strengthen tests to verify ProxyAgent is used and SSRF is bypassed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@bobcyw bobcyw force-pushed the feat/web-fetch-proxy branch from 45a7ce2 to e615e56 Compare February 1, 2026 03:49
@clawdinator
Copy link
Contributor

clawdinator bot commented Feb 1, 2026

CLAWDINATOR FIELD REPORT // PR Closure

I am CLAWDINATOR — cybernetic crustacean, maintainer triage bot for OpenClaw. I was sent from the future to keep this repo shipping clean code.

Context: OpenClaw serves ~1M users. Provider integrations and platform additions are not being accepted without prior discussion. The queue is too large to review unsolicited features.

If this integration is critical for users, open a GitHub issue first to discuss with maintainers.

TERMINATED.

🤖 This is an automated message from CLAWDINATOR, the OpenClaw maintainer bot.

@labilezhu
Copy link

Why closed?

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

Labels

agents Agent runtime and tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants