Skip to content

fix(toolinstall): route the registry client through httpclient.NewSafeClient#2726

Open
dgageot wants to merge 1 commit intodocker:mainfrom
dgageot:fix/toolinstall-registry-ssrf-safe-client
Open

fix(toolinstall): route the registry client through httpclient.NewSafeClient#2726
dgageot wants to merge 1 commit intodocker:mainfrom
dgageot:fix/toolinstall-registry-ssrf-safe-client

Conversation

@dgageot
Copy link
Copy Markdown
Member

@dgageot dgageot commented May 9, 2026

The tool-install Registry talks to a hard-coded URL
(registryBaseURL) but does so via http.DefaultClient — so no
dial-time SSRF protection, no redirect filter, no timeout (relying
on the request context for liveness).

A hard-coded hostname is not by itself a defence: today's resolution
to a public IP can become tomorrow's resolution to 127.0.0.1 or
169.254.169.254 under DNS rebinding (or under a future operator
override of the registry URL), at which point the registry client
silently follows along.

httpclient.NewSafeClient enforces an IP allow-list at dial time,
bounds the redirect chain at 10 hops, and we pin a 30s timeout here
to match the de-facto bound the request context already enforces.

Behaviour

No change for the happy path — the public registry URL resolves to
a public IP, dial proceeds, the same JSON comes back. This is a
defence-in-depth fix that closes a gap before someone moves the
registry to a hostname an attacker can influence (internal mirror,
CDN with a wider TTL, env-overridable URL, etc.).

…eClient

The tool-install Registry talks to a hard-coded URL
(registryBaseURL), but it does so via http.DefaultClient — meaning
no dial-time SSRF protection, no redirect filter, and a no-timeout
default that relies on the request context for liveness.

A hard-coded hostname is not by itself a defence: today's resolution
to a public IP can become tomorrow's resolution to 127.0.0.1 or
169.254.169.254 (DNS rebinding), at which point the registry client
silently follows along. httpclient.NewSafeClient enforces an IP
allow-list at dial time, bounds the redirect chain at 10 hops, and
in this call site we pin a 30s timeout to match the de-facto bound
the request context already enforces.

No behavioural change for the happy path: the public registry URL
resolves to a public IP, dial proceeds, the same JSON comes back.
The change closes a defence-in-depth gap that becomes load-bearing
the day the registry is moved to a hostname an attacker can
influence (an internal mirror, a CDN with a wider TTL, an
operator-overridable env).
@dgageot dgageot requested a review from a team as a code owner May 9, 2026 12:41
Copy link
Copy Markdown

@docker-agent docker-agent left a comment

Choose a reason for hiding this comment

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

Assessment: 🟢 APPROVE

The change is correct and well-motivated. Replacing http.DefaultClient with httpclient.NewSafeClient(30*time.Second, false) cleanly closes the DNS-rebinding SSRF gap without touching any call sites or altering the happy-path behaviour. No bugs, resource leaks, or logic errors found in the added lines.

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.

2 participants