transport: allow bearer realm at same host:port as registry#2302
Merged
Conversation
Subserial
requested changes
May 18, 2026
Subserial
left a comment
Contributor
There was a problem hiding this comment.
LGTM, but can you reduce the long comments? Just mentioning "always allow realm URLs matching the registry URL" is fine.
Contributor
Author
|
Sure, I will push the changs with short commetns... |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2302 +/- ##
==========================================
+ Coverage 56.89% 56.92% +0.02%
==========================================
Files 165 165
Lines 11331 11333 +2
==========================================
+ Hits 6447 6451 +4
+ Misses 4120 4119 -1
+ Partials 764 763 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Fixes google#2258. The realm-URL validation introduced in google#2243 rejects realms whose host resolves to a private, loopback, or link-local IP. This is the right default for the cross-host SSRF case (a malicious registry pointing the token endpoint at 169.254.169.254 or a sister internal service), but it breaks legitimate setups where a user explicitly targets a private/loopback registry that returns a same-host token endpoint — e.g. test suites that run an authenticated registry on 127.0.0.1, or on-prem deployments that colocate the registry and its token server. Add a same-host:port exception: if the realm URL host:port equals the registry host:port the user is already talking to, skip the private/ link-local check. The realm is not crossing a trust boundary the user did not already trust by passing the reference. The match is strict (host AND port) so that "different port on the same loopback host" attacks — e.g. a realm pointed at a local database or metadata-service port — remain blocked. Mirrors the same-host exception pattern already used by the blob upload Location-header check in pkg/v1/remote/write.go. Signed-off-by: iahsanGill <mgill.bese22seecs@seecs.edu.pk>
bc8aa5f to
861caba
Compare
Subserial
approved these changes
May 18, 2026
jimmidyson
added a commit
to mesosphere/mindthegap
that referenced
this pull request
May 19, 2026
Bump google/go-containerregistry from v0.21.5 to v0.21.6 to include google/go-containerregistry#2302 (transport: allow bearer realm at same host:port as registry). The realm-URL validation introduced in go-containerregistry#2243 (shipped in v0.21.5) rejects realms whose host resolves to a private, loopback, or link-local IP. This is the right default for the cross-host SSRF case (a malicious registry pointing the token endpoint at 169.254.169.254 or a sister internal service), but it breaks `mindthegap push bundle` (and downstream `nkp push bundle`) against on-prem registries that colocate the registry and bearer- token endpoint on the same private IP. e.g. for an internal Harbor at https://10.162.182.23:5000/library the push aborts with: invalid realm in www-authenticate: realm host "10.162.182.23" is a private or link-local address v0.21.6 keeps the cross-host SSRF block but adds a same-host:port exception: when the realm URL host AND port match the registry, the private-IP check is skipped. The realm cannot escape a trust boundary the user already crossed by passing the registry reference. The transitive bumps (docker/cli, moby/moby, docker/go-connections, klauspost/compress, golang.org/x/{crypto,mod,net,sys,term,text, tools}) are pulled in by go-containerregistry v0.21.6 go.mod via MVS resolution. The containerd/stargz-snapshotter/estargz and vbatts/tar-split indirect dependencies are dropped because v0.21.6 removed estargz support (go-containerregistry#2288). Test expectations in images/manifest_test.go are updated for the unrelated OCI-spec compliance change in google/go-containerregistry#2269: mutate.AppendManifests now sets the index entry ArtifactType to the image Config.MediaType when the image manifest does not itself set artifactType. For the Docker schema2 fixture in TestManifestListForImage_RemoteImage this becomes "application/vnd.docker.container.image.v1+json" (types.DockerConfigJSON).
jimmidyson
added a commit
to mesosphere/mindthegap
that referenced
this pull request
May 19, 2026
…223) (#1046) ## Summary - Bump `github.com/google/go-containerregistry` v0.21.5 → v0.21.6 to pick up [google/go-containerregistry#2302](google/go-containerregistry#2302) — transport: allow bearer realm at same host:port as registry. - Fixes [NCN-114223](https://jira.nutanix.com/browse/NCN-114223): `mindthegap push bundle` (and downstream `nkp push bundle`) regression against on-prem registries that colocate the registry and bearer-token endpoint on the same private IP. e.g. for an internal Harbor at `https://10.162.182.23:5000/library` the push aborted with `invalid realm in www-authenticate: realm host "10.162.182.23" is a private or link-local address`. - Add regression test `TestPushDockerArchive_BearerAuthSameHostLoopbackRealm` in `cmd/mindthegap/push/imagearchive/push_test.go` that reproduces the exact NCN-114223 error against v0.21.5 and passes against v0.21.6. ## Background The realm-URL validation introduced in [go-containerregistry#2243](google/go-containerregistry#2243) (shipped in v0.21.5) rejects realms whose host resolves to a private, loopback, or link-local IP. This is the right default for the cross-host SSRF case (a malicious registry pointing the token endpoint at `169.254.169.254` or a sister internal service), but it broke legitimate on-prem deployments that serve their own token endpoint at the same host:port as the registry. [#2258](google/go-containerregistry#2258) tracked the discussion; [#2302](google/go-containerregistry#2302) implements the agreed fix: keep the cross-host SSRF block, but skip the private-IP check when the realm URL host AND port match the registry host:port. ## Transitive dependency changes Pulled in by `go-containerregistry` v0.21.6's `go.mod` via MVS resolution: - `docker/cli` v29.4.0 → v29.4.3 - `moby/moby/api` v1.54.1 → v1.54.2 - `moby/moby/client` v0.4.0 → v0.4.1 - `docker/go-connections` v0.6.0 → v0.7.0 - `klauspost/compress` v1.18.5 → v1.18.6 - `golang.org/x/{crypto,mod,net,sys,term,text,tools}` — minor bumps Dropped (v0.21.6 removed estargz support in [go-containerregistry#2288](google/go-containerregistry#2288)): - `containerd/stargz-snapshotter/estargz` (indirect) - `vbatts/tar-split` (indirect) ## Test fixture update `images/manifest_test.go` is updated for the unrelated OCI-spec compliance change in [go-containerregistry#2269](google/go-containerregistry#2269): `mutate.AppendManifests` now sets the index entry `ArtifactType` to the image's `Config.MediaType` when the image manifest does not itself set `artifactType`. For the Docker schema2 fixture in `TestManifestListForImage_RemoteImage` this becomes `"application/vnd.docker.container.image.v1+json"` (`types.DockerConfigJSON`). ## Test plan - [x] `go test -count=1 ./...` passes (155 tests). - [x] New `TestPushDockerArchive_BearerAuthSameHostLoopbackRealm` fails on v0.21.5 with the exact NCN-114223 error (`invalid realm in www-authenticate: realm host "127.0.0.1" is a private or link-local address`) and passes on v0.21.6 — bisected to confirm it is not a tautology. - [x] `go build ./...` passes. - [x] `golangci-lint run ./...` clean. - [ ] Manual verification against an on-prem Harbor with realm host == registry host on an RFC1918 IP (e.g. the reproducer environment in NCN-114223). ## Out of scope The two pre-existing govulncheck stdlib findings (`GO-2026-4982`, `GO-2026-4980`, `GO-2026-4971`, `GO-2026-4918` — all `go1.25.x` fixed in `go1.25.10`) are unrelated to this change.
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
Fixes #2258.
The realm-URL validation introduced in #2243 rejects realms whose host resolves to a private, loopback, or link-local IP. This is the right default for the cross-host SSRF case (a malicious registry pointing the token endpoint at
169.254.169.254or at a sister internal service), but it breaks legitimate setups where a user explicitly targets a private/loopback registry that returns a same-host token endpoint — e.g. test suites running an authenticated registry on127.0.0.1, or on-prem deployments that colocate registry and token server.This PR adds the same-host:port exception agreed in the issue thread (cc @evilgensec, @Subserial): if the realm URL host:port equals the registry host:port the user is already talking to, the private/link-local check is skipped. The realm is by definition not crossing a trust boundary the user did not already trust by passing the reference.
The match is strict — host and port — so that the "different port on the same loopback host" case (e.g. a realm pointed at a local database or metadata-service port that happens to live alongside the registry) remains blocked.
This mirrors the same-host exception pattern already used by the blob upload Location-header check in
pkg/v1/remote/write.go.Changes
validateRealmURLregistryHostparameter; returnnilearly whenu.Host == registryHost. Scheme check still applies.realmRedirectCheckregistryHostthrough tovalidateRealmURLso redirects honor the same exception.fromChallengecallsitereg.RegistryStr().refreshOauth/refreshBasiccallsitesbt.registry.RegistryStr().TestValidateRealmURLUnspecifiedregistryHostpreserves prior behavior).TestValidateRealmURLSameHost(new)pkg/v1/remote/...tests all pass locally;go vet ./pkg/v1/remote/transport/...clean.Out of scope
localhost(DNS) to the private blocklist, as suggested by @evilgensec in the issue. That would be a separate change to the threat-model surface and worth its own PR.Retry-Afteron transport-level retries (separate follow-up to transport: retry HTTP 429 (Too Many Requests) #2301).Test plan
TestValidateRealmURLSameHost— table-driven, 7 casesTestValidateRealmURLUnspecified— still passes with new signatureTestTokenServerRedirectSSRF— still rejects cross-host redirects after the closure signature changego test ./pkg/v1/remote/...green