transport: validate Bearer realm URL to prevent SSRF#2243
transport: validate Bearer realm URL to prevent SSRF#2243Subserial merged 3 commits intogoogle:mainfrom
Conversation
fromChallenge() stored the realm value from a WWW-Authenticate header verbatim without validation. A malicious or MITM'd registry could supply a realm pointing at a private/link-local address (e.g. 169.254.169.254) or use a non-HTTP scheme, causing the client to make token-fetch requests to internal services when pulling images. Add validateRealmURL() which enforces: - Scheme allowlist: only https is accepted for secure registries; http is additionally accepted when the registry is marked insecure. - IP literal blocklist: loopback, link-local unicast/multicast, and private-range addresses are rejected. This blocks direct SSRF to cloud instance metadata services and RFC 1918 networks. DNS-based SSRF is out of scope and should be handled at the network layer.
|
The security report URL seems to be incorrect. The referenced issue seems unrelated. |
|
Dear @Subserial, I have updated the report url: https://issuetracker.google.com/issues/495960898 As the security tab of the program instructs to report vulnerabilities through google bug hunter, I have done so. If anything else is needed please let me know. |
|
@Subserial Hope you are doing well. Is there any update on the issue? |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2243 +/- ##
===========================================
- Coverage 71.67% 52.96% -18.72%
===========================================
Files 123 165 +42
Lines 9935 11215 +1280
===========================================
- Hits 7121 5940 -1181
- Misses 2115 4561 +2446
- Partials 699 714 +15 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Foreign layer descriptors in image manifests can contain arbitrary URLs in the "urls" field. When the registry blob endpoint returns 404, the client fetches these URLs with no validation, allowing a malicious registry to trigger requests to internal services (SSRF). Add validateForeignURL() to reject foreign layer URLs that use non-HTTP(S) schemes or reference private, loopback, link-local, or unspecified IP addresses. This is consistent with the existing validateRealmURL() protection added in PR google#2243 for Bearer auth realm URLs. DNS-based SSRF remains out of scope, matching the design decision in validateRealmURL().
Foreign layer descriptors in image manifests can contain arbitrary URLs in the "urls" field. When the registry blob endpoint returns 404, the client fetches these URLs with no validation, allowing a malicious registry to trigger requests to internal services (SSRF). Add validateForeignURL() to reject foreign layer URLs that use non-HTTP(S) schemes or reference private, loopback, link-local, or unspecified IP addresses. This is consistent with the existing validateRealmURL() protection added in PR google#2243 for Bearer auth realm URLs. DNS-based SSRF remains out of scope, matching the design decision in validateRealmURL().
Summary
fromChallenge()stored therealmvalue from aWWW-Authenticate: Bearerheader verbatim, with no validation of scheme or destination host. When the client subsequently fetched a token, it made an HTTP request to whatever URL the registry supplied — including private/link-local addresses and non-HTTP schemes.Root cause:
Attack scenario: An attacker-controlled registry (or MITM on an HTTP registry connection) returns:
The client sends a GET to the AWS/GCP instance metadata endpoint, leaking IAM credentials. The basic credentials sent with the token request are also leaked to the attacker-controlled realm.
This affects all tools using
go-containerregistryfor pulls:crane,ko, Kubernetes admission controllers, and CI/CD pipelines.Fix
Add
validateRealmURL()called fromfromChallenge()before storingrealm:httpsfor secure registries;httpadditionally allowed for insecure registriesRelated security report: https://issuetracker.google.com/issues/495960898