fix(opencode): close webfetch SSRF redirect bypass, fix IP range checks, harden response handling#36377
Open
sontani2017 wants to merge 1 commit into
Open
fix(opencode): close webfetch SSRF redirect bypass, fix IP range checks, harden response handling#36377sontani2017 wants to merge 1 commit into
sontani2017 wants to merge 1 commit into
Conversation
- webfetch: follow redirects manually (redirect: manual via FetchHttpClient.RequestInit) and re-validate every hop against the SSRF guard, with a 5-redirect cap and non-http(s) targets refused; previously a permitted public URL could 302 to an internal address (e.g. 169.254.169.254) and be followed silently - webfetch: replace string-matching IPv6 checks with a real parser (:: expansion, dotted-quad tails, zone ids) covering fe80::/10, fec0::/10, fc00::/7, ff00::/8, IPv4-mapped, NAT64 and 6to4 embeds; add missing IPv4 reserved ranges (192.0.0.0/24, TEST-NETs, 198.18.0.0/15, multicast/reserved/broadcast) - webfetch: block *.internal hosts and trailing-dot bypass (localhost.); stream response body with early abort at the 5MB cap - webfetch: add AllowPrivateFetch context reference (default: guard enforced) with OPENCODE_WEBFETCH_ALLOW_PRIVATE env opt-out so local dev servers remain fetchable; integration tests provide it explicitly - .opencode: repair github-pr-search.ts (file was truncated mid-statement and could not load); split pure helpers of both plugin tools into .opencode/lib with unit tests; page-based pagination and state filter for PR search - tests: SSRF/extract/permission-semantics suites; redirect-follow, redirect-cap and guard-enforcement integration tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes #36376
Type of change
What does this PR do?
Fixes the webfetch SSRF and robustness problems described in #36376:
FetchHttpClient, and fetch follows redirects on its own — so a permitted public URL could 302 tohttp://169.254.169.254/(or any internal host) and be fetched silently. This PR setsredirect: "manual"via theFetchHttpClient.RequestInitcontext and follows redirects in the tool itself, re-running the guard on every hop (max 5, non-http(s) targets refused). The Cloudflare 403-challenge retry is kept inside the loop.0:0:0:0:0:0:0:1passed as public, only the literal prefixfe80of fe80::/10 was caught, and NAT64/6to4-embedded IPv4 plus several reserved IPv4 ranges (TEST-NETs, 198.18.0.0/15, 192.0.0.0/24, multicast/reserved) were missed. Replaced with a real IPv6 parser (::expansion, dotted-quad tails, zone ids) and complete range tables. Hostname checks also cover*.internaland trailing dots (localhost.).extractTextFromHTMLskip-tracking no longer desyncs on void elements inside<script>/<style>regions (tag-name-based tracking).Bun.serveon localhost), so there is anAllowPrivateFetchcontext reference: guard enforced by default,OPENCODE_WEBFETCH_ALLOW_PRIVATE=1opts out (the refusal message says so), tests provide it explicitly..opencode/tool/github-pr-search.ts: page-based pagination replaces the offset math that could overlap/skip results, adds astatefilter, stops sendingContent-Typeon GET; pure helpers of both.opencodetools split into.opencode/libwith unit tests.permission.ts/wildcard.tschanges are documentation comments only, pinned by a newpermission/semantics.test.ts.One known remaining gap, documented in the code: DNS rebinding cannot be fully closed without pinning the resolved IP into the connection, which fetch does not expose.
How did you verify your code works?
bun testinpackages/opencode: webfetch integration suite (incl. new redirect-follow, redirect-cap, and guard-enforcement tests),webfetch-ssrf(49 IP/URL cases),webfetch-extract, and permission semantics — 175 tests passbun testin.opencode: 21 tests passbun turbo typecheckpasses across the monorepoScreenshots / recordings
Not a UI change.
Checklist
🤖 Generated with Claude Code