Skip to content

[eric] web: guard WebFetch against SSRF (scheme + per-redirect private-IP block)#57

Closed
ciregenz wants to merge 1 commit into
mainfrom
eric/ssrf-a
Closed

[eric] web: guard WebFetch against SSRF (scheme + per-redirect private-IP block)#57
ciregenz wants to merge 1 commit into
mainfrom
eric/ssrf-a

Conversation

@ciregenz

Copy link
Copy Markdown
Collaborator

Closes #47

What

WebFetch is the agent's built-in URL fetcher. The agent chooses which URL to hit, and that choice can be steered by content on pages it already read (prompt injection). The old guard was scheme-only (in the MCP shim) and follow_redirects=True, so http://169.254.169.254/, http://192.168.x.x/, and http://127.0.0.1:8324/ all sailed through, and even a public URL could 30x-pivot into the LAN.

Fix

New backend/apps/agents/tools/url_guard.py:

  • validate_fetch_url: rejects non-http(s) schemes; rejects any host that is (or resolves to) a private, loopback, link-local, reserved, multicast, unspecified, or otherwise non-global IP. IP literals are checked as-is so a DNS-rebind literal can't slip past.
  • fetch_guarded: follows redirects manually (httpx follow_redirects=False) and re-validates every hop before the request, closing the redirect-pivot hole.

WebFetchTool.execute now routes through fetch_guarded and returns a clean "Refused to fetch ..." tool message on a block. This is the single chokepoint both the agent path and the REST /api/web/fetch local fallback funnel through. Provider-grounded fetches (Gemini/OpenAI url-context) run on the provider's servers, not the user's LAN, so they aren't in scope.

Verify

  • 19 new unit tests in backend/tests/test_url_guard.py (schemes, IPv4/IPv6 internal literals, cloud-metadata, redirect-to-internal blocked before the request fires, redirect-loop cap). All green.
  • End-to-end: WebFetchTool.execute refuses metadata/loopback/file://; public fetch of example.com and an http->https redirect (github.com) still work with content extraction intact.
  • verify-all.js is the packaged-DMG verifier (boot/signing/python-health); it doesn't exercise WebFetch and needs a built app, so it's N/A for this backend-logic change. Verified via pytest instead.

🤖 Generated with Claude Code

@ciregenz

Copy link
Copy Markdown
Collaborator Author

Closing: opened by an automated run-all cycle, not wanted. The SSRF fix for #47 is already covered by community PR #51.

@ciregenz ciregenz closed this May 31, 2026
@ciregenz
ciregenz deleted the eric/ssrf-a branch May 31, 2026 23:29
many221 pushed a commit to many221/openswarm that referenced this pull request Jun 1, 2026
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.

SSRF: WebFetch tool fetches arbitrary internal/cloud URLs with no host validation

1 participant