Skip to content

Centralise outbound URL validation in StrictHTTPClient#4246

Open
JorisHeadease wants to merge 2 commits into
masterfrom
refactor/4244-centralise-url-validation
Open

Centralise outbound URL validation in StrictHTTPClient#4246
JorisHeadease wants to merge 2 commits into
masterfrom
refactor/4244-centralise-url-validation

Conversation

@JorisHeadease
Copy link
Copy Markdown
Contributor

Closes #4244.

What changed

  • http/client.StrictHTTPClient.Do now validates every outbound URL via core.ParsePublicURL, gated by the global http/client.StrictMode flag.
  • CheckRedirect is wired on all three constructors so every redirect target is re-validated (10-hop cap matches net/http's default).
  • Per-caller URL validation removed from auth/openid4vci.Client, auth/client/iam.HTTPClient.ClientMetadata, and the scheme-only check in auth/services/oauth/relying_party.RequestRFC003AccessToken — all production callers route through *StrictHTTPClient.

Behavior change

Strict mode now rejects IP literals (e.g. https://10.0.0.1/) and RFC 2606 reserved hostnames (*.localhost, *.test, example.com/net/org, etc.) on every outbound HTTP request, not just OpenID4VCI. Previously only the HTTPS-scheme check was enforced for most callers. Deployments using IP hosts or reserved TLDs as Nuts service endpoints will need real DNS names. Redirects to such targets are also blocked.

Breaking API change

oauth.NewRelyingParty no longer accepts a strictMode bool parameter. Strict-mode behaviour is now controlled exclusively by http/client.StrictMode, which the HTTP engine sets at startup from core.ServerConfig.Strictmode.

A backward-compatible stub was considered and rejected: silently ignoring the argument would create a footgun where callers pass strictMode=true but get whatever the global flag happens to be. External consumers can update by removing the argument from the call site.

Out of scope

DNS rebinding and public hostnames resolving to private IPs (e.g. 10.0.0.1.nip.io, metadata.google.internal) are not defended — core.ParsePublicURL validates the URL string, not the resolved address. Closing this gap requires a custom DialContext and should be tracked separately.

Move core.ParsePublicURL from per-caller into StrictHTTPClient.Do so every
outbound HTTP request gets HTTPS-only + no-IP + no-RFC2606-reserved-host
validation in strict mode. Add CheckRedirect to re-validate every redirect
target (10-hop cap matches net/http's default).

Removes the duplicated validation in auth/openid4vci.Client,
auth/client/iam.HTTPClient.ClientMetadata, and the scheme-only check in
auth/services/oauth/relying_party.RequestRFC003AccessToken. All production
callers route through *StrictHTTPClient.

Behavior change: strict mode now rejects IP literals and RFC 2606 reserved
hostnames on every outbound HTTP request, not just OpenID4VCI.

Breaking API: oauth.NewRelyingParty no longer accepts a strictMode bool
parameter; strict-mode behaviour is now controlled exclusively by the
http/client.StrictMode flag set by the HTTP engine at startup.

Closes #4244
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Centralizes SSRF-oriented outbound URL validation inside http/client.StrictHTTPClient so all outbound HTTP calls (and redirect targets) are consistently validated via core.ParsePublicURL, and removes duplicated per-caller checks across auth-related clients.

Changes:

  • Validate every outbound request URL in StrictHTTPClient.Do via core.ParsePublicURL, gated by the global http/client.StrictMode.
  • Enforce URL validation on redirects by wiring CheckRedirect (with a 10-hop cap) into all StrictHTTPClient constructors.
  • Remove per-caller strict-mode URL checks and adjust APIs/tests/docs accordingly (incl. dropping strictMode from oauth.NewRelyingParty and openid4vci.NewClient).

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
http/client/client.go Adds centralized ParsePublicURL validation and redirect re-validation via CheckRedirect.
http/client/client_test.go Updates strict-mode error expectations and adds coverage for IP/reserved-host blocking + redirects.
auth/openid4vci/client.go Removes per-client URL validation and drops strictMode parameter from NewClient.
auth/openid4vci/client_test.go Updates construction of the OpenID4VCI client to match the new API.
auth/client/iam/client.go Removes per-method URL validation for client metadata retrieval (now inherited from shared HTTP client).
auth/services/oauth/relying_party.go Removes relying-party strictMode parameter/field; relies on shared HTTP client strict mode.
auth/services/oauth/relying_party_test.go Removes tests that exercised relying-party-local scheme validation (now centralized).
auth/auth.go Updates call sites for the changed openid4vci.NewClient and oauth.NewRelyingParty signatures.
vcr/vcr_test.go Updates strict-mode error assertions to match new centralized validation errors.
docs/pages/deployment/configuration.rst Documents stricter outbound URL validation (IP literals + RFC2606 reserved hosts) and redirect enforcement.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread http/client/client_test.go Outdated
Comment thread http/client/client_test.go Outdated
Comment thread vcr/vcr_test.go Outdated
Apply the capture-and-restore t.Cleanup pattern to tests that mutate the
package-level StrictMode and DefaultCachingTransport globals so they no
longer leak state into subsequent tests. Adds a withClientGlobals helper
in http/client/client_test.go to avoid repeating the boilerplate.

Also fixes a pre-existing DefaultCachingTransport leak in TestCaching.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

@JorisHeadease JorisHeadease marked this pull request as ready for review May 11, 2026 18:00
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.

Centralise outbound URL validation in StrictHTTPClient

2 participants