cmd/go: reject sumdb response lacking module hash

Report an error when a sumdb /lookup/ request does not
include a hash for the requested module, rather than
silently proceeding.

Previously, we would verify that a returned sum matched
the expected module hash, but did not verify that the
response contained a sum. This permits a malicous
proxy to serve a corrupted module along with a
valid-but-irrelevant sumdb response for some other
module. We now ensure that the sumdb response contains
a valid hash for the module we are validating.

Thanks to Mundur (https://github.com/M0nd0R) for reporting this issue.

Fixes CVE-2026-42501
Fixes #79070

Change-Id: I7d9a367deb237aa70cade2434495998f6a6a6964
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/4340
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Neal Patel <nealpatel@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/775321
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Damien Neil 2026-04-30 13:10:49 -07:00 committed by Cherry Mui
parent 788b1c54c1
commit 1a9af07120
3 changed files with 48 additions and 1 deletions

View file

@ -870,7 +870,7 @@ func checkSumDB(mod module.Version, h string) error {
return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, noun, h, db, line[len(prefix)-len("h1:"):]))
}
}
return nil
return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: checksum missing from sumdb response"+sumdbAbsent, noun))
}
// Sum returns the checksum for the downloaded copy of the given module,
@ -1080,6 +1080,19 @@ have intercepted the download attempt.
For more information, see 'go help module-auth'.
`
const sumdbAbsent = `
SECURITY ERROR
This download does NOT match one reported by the checksum server.
The checksum server has provided checksums, but the checksums do
not contain an entry for the download.
The checksum server may be malfunctioning, or an attacker may have
intercepted the checksum request.
The download cannot be verified.
For more information, see 'go help module-auth'.
`
const hashVersionMismatch = `
SECURITY WARNING

View file

@ -172,6 +172,23 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Request for $GOPROXY/sumdb-redirect/module@version:/lookup/...
// performs a lookup for module@version rather than the requested module.
if strings.HasPrefix(path, "sumdb-redirect/") {
redirect, rest, ok := strings.Cut(path[len("sumdb-redirect"):], ":")
if !ok {
w.WriteHeader(500)
return
}
if strings.HasPrefix(rest, "/lookup/") {
r.URL.Path = "/lookup" + redirect
} else {
r.URL.Path = rest
}
sumdbServer.ServeHTTP(w, r)
return
}
// Request for $GOPROXY/redirect/<count>/... goes to redirects.
if strings.HasPrefix(path, "redirect/") {
path = path[len("redirect/"):]

View file

@ -0,0 +1,17 @@
# When the sumdb returns a response which does not
# include a sum for the requested module,
# we should report an error.
# Verifies CVE-2026-42501.
env sumdb=$GOSUMDB
env proxy=$GOPROXY
env GOPROXY GONOPROXY GOSUMDB GONOSUMDB
# /sumdb-redirect/ causes the sumdb to return /lookup/ responses
# for rsc.io/quote@v1.0.0, not for the requested module.
env GOSUMDB=$sumdb' '$proxy/sumdb-redirect/rsc.io/quote@v1.0.0:
! go get rsc.io/fortune@v1.0.0
stderr 'SECURITY ERROR'
! grep rsc.io go.sum
-- go.mod --
module m