Block private and loopback dials in webhook HTTP client#5190
Open
Block private and loopback dials in webhook HTTP client#5190
Conversation
3 tasks
A tenant with rights to create MCPWebhookConfig could previously point url at any HTTPS endpoint, including 169.254.169.254, 127.0.0.1, RFC1918 ranges, and IPv6 loopback or link-local addresses. The webhook HTTP transport built a bare http.Transport with no DialContext; the wrapping networking.ValidatingTransport only checks the URL scheme, not the resolved peer address, so cross-tenant access to cloud metadata or in-cluster services was unblocked. Wire networking.ProtectedDialerControl into the inner transport's DialContext so private, loopback, and link-local destinations are rejected at dial time, regardless of whether ValidatingTransport's HTTPS check is bypassed via InsecureAllowHTTP. The hook is held in an atomic.Pointer so test overrides remain race-free if a future test introduces t.Parallel(). Export protectedDialerControl as ProtectedDialerControl in pkg/networking so the webhook package can install it without duplicating the body. Add cross-package test injection (SetDialerControlForTesting, SetDialerControlForTestMain, AllowAnyDialerControl) so existing httptest-based tests in pkg/webhook and its subpackages continue to work; subpackage TestMain functions install the permissive override at suite startup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f1ad404 to
a48d30f
Compare
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.
Summary
Follow-up to the round-2 review of #4564 (item #5). A tenant with rights to create
MCPWebhookConfigcould previously pointurlat any HTTPS endpoint, including169.254.169.254(cloud metadata),127.0.0.1, RFC1918 ranges, and IPv6 loopback / link-local / ULA addresses. The webhook HTTP transport built a barehttp.Transportwith noDialContext; the wrappingnetworking.ValidatingTransportonly checks the URL scheme — it does not validate the resolved peer address — so cross-tenant access to cloud metadata or in-cluster services was unblocked.This PR wires
networking.ProtectedDialerControlinto the inner transport'sDialContextso private, loopback, and link-local destinations are rejected at dial time, regardless of whetherValidatingTransport's HTTPS check is bypassed viaInsecureAllowHTTP. The hook is held in anatomic.Pointerso test overrides remain race-free if a future test introducest.Parallel().protectedDialerControlis exported asProtectedDialerControlinpkg/networkingso the webhook package can install it without duplicating the body. Cross-package test injection (SetDialerControlForTesting,SetDialerControlForTestMain,AllowAnyDialerControl) is added so the existing httptest-based suite inpkg/webhookand its subpackages keeps working; subpackageTestMainfunctions install the permissive override at suite startup.Type of change
Test plan
task test—pkg/webhook/...andpkg/networking/...pass with-race)golangci-lintreports 0 issues)TestClientSSRFGuardBlocksPrivateAddresscovers IPv4 loopback, RFC1918, and169.254.169.254, plus IPv6 loopback (::1), link-local (fe80::1), and ULA (fc00::1).TestBuildTransportInstallsDialerGuardassertsDialContextis wired on the inner transport.Special notes for reviewers
pkg/webhook/dialer_testing.goadd public surface area in service of cross-package test injection. A reviewer raised the option of moving them to apkg/webhook/internal/dialersubpackage; that's a viable follow-up but feels like scope creep here. Each helper has aProduction code MUST NOT call this functiondeterrent in its godoc and thetesting.TBargument signals test-scoped intent.InsecureSkipVerifyconflates cert-skip with plaintext-HTTP) and item Implement secret injection #5's broader IPv6 coverage inpkg/networkingitself are tracked separately.🤖 Generated with Claude Code