validateRealmURL() in pkg/v1/remote/transport/bearer.go checks IsLoopback, IsPrivate, IsLinkLocalUnicast, and IsLinkLocalMulticast but not IsUnspecified.
0.0.0.0 and :: pass all four checks, but on Linux and macOS they resolve to 127.0.0.1. A malicious container registry can redirect auth requests to the victim's localhost by returning:
WWW-Authenticate: Bearer realm="https://0.0.0.0:9999/token",service="registry"
The client then sends Basic auth credentials to localhost:9999 — credential theft.
Confirmed with a PoC:
net.ParseIP("0.0.0.0").IsLoopback() = false
net.ParseIP("0.0.0.0").IsPrivate() = false
net.ParseIP("0.0.0.0").IsUnspecified() = true (not checked)
net.Dial("tcp", "0.0.0.0:PORT") connects to 127.0.0.1
I'll submit a PR adding ip.IsUnspecified() to the existing check.
validateRealmURL()inpkg/v1/remote/transport/bearer.gochecksIsLoopback,IsPrivate,IsLinkLocalUnicast, andIsLinkLocalMulticastbut notIsUnspecified.0.0.0.0and::pass all four checks, but on Linux and macOS they resolve to127.0.0.1. A malicious container registry can redirect auth requests to the victim's localhost by returning:The client then sends Basic auth credentials to
localhost:9999— credential theft.Confirmed with a PoC:
net.ParseIP("0.0.0.0").IsLoopback()= falsenet.ParseIP("0.0.0.0").IsPrivate()= falsenet.ParseIP("0.0.0.0").IsUnspecified()= true (not checked)net.Dial("tcp", "0.0.0.0:PORT")connects to 127.0.0.1I'll submit a PR adding
ip.IsUnspecified()to the existing check.