Open Source Security

Go Module Checksum Database In Depth

The Go checksum database is one of the most successful supply chain controls in any mainstream ecosystem. Here is how it actually works and where it still has edges.

Shadab Khan
Security Engineer
6 min read

The Go module checksum database, operated by Google at sum.golang.org, is one of the quietly great supply chain controls in mainstream software. It predates the current generation of attestation and transparency-log work and has been running in production for years with very few user-facing incidents. Most Go developers never think about it, which is exactly what a well-designed security primitive should look like. But "never think about it" is not the same as "never needs to be understood," and in 2026 the checksum database is showing some interesting edges worth knowing about.

What does the Go checksum database actually guarantee?

The checksum database is a Merkle-tree-backed transparency log of module hashes. When your build asks for example.com/foo v1.2.3, the Go toolchain fetches the module and its hash, then checks that hash against what the checksum database has on record for that version. If nobody has ever seen that version before, the database records the hash as the first observation. If someone has seen it, the database returns the previously recorded hash, and the toolchain refuses to use a module whose content does not match.

The guarantee is consistency, not authenticity. The database does not know whether the first observation was genuine; it only guarantees that everyone who asks about a specific module version gets the same answer. This is a weaker property than signed attestations, but it is enough to stop a very large class of attacks. Once a module version has been published and observed, the upstream cannot silently replace its content without every verifying client detecting the mismatch.

How does GOSUMDB interact with GOPROXY in practice?

GOPROXY controls where you fetch module content from. GOSUMDB controls where you verify hashes. These are independent, and teams who conflate them end up with configurations that look secure but are not. Setting GOPROXY=direct and leaving GOSUMDB enabled gives you direct-from-VCS fetches with centralized hash verification, which is fine. Setting GOPROXY to a private proxy and also setting GOSUMDB=off gives you a private proxy with no external verification, which is a much weaker posture than it looks.

The configuration that catches people is a private GOPROXY that also speaks the checksum database protocol and is configured via GOSUMDB=<private-sumdb>. This is supported and reasonable for air-gapped environments, but it moves the entire trust anchor into your proxy operator. If your proxy is compromised, your checksum verification is compromised along with it. The public checksum database's value is precisely that it is an independent trust anchor; internalizing it trades off security properties for operational control.

When should you actually turn off the checksum database?

Rarely, and only with a specific plan. The legitimate cases are private modules on internal VCS paths that the public database cannot reach, and truly air-gapped environments where reaching sum.golang.org is not possible. For both, the right move is not GOSUMDB=off but GONOSUMCHECK scoped to specific module paths, or a properly configured private sumdb.

What I see in real-world configurations is GOSUMDB=off in Dockerfiles, copied from Stack Overflow answers from 2019, applied to container builds that do have network access and absolutely could use the database. This is the single most common Go supply chain misconfiguration I see in audits, and it is entirely avoidable. If your Go build has internet access for module fetching, it has internet access for checksum verification, and turning one on without the other is a mistake.

What does the Go vulnerability database add on top?

The Go vulnerability database at vuln.go.dev complements the checksum database by recording known vulnerabilities in module versions. govulncheck cross-references your actual call graph against the database and reports only vulnerabilities you actually reach, which cuts noise dramatically compared to traditional dependency scanners. This is one of the features I point to when people ask why Go's supply chain story is better than its peers'.

The limitation is that the vulnerability database, like any curated database, has coverage gaps and reporting lag. For widely-used modules, coverage is good. For long-tail modules, coverage thins out fast. And govulncheck's call-graph analysis is conservative: it will tell you a vulnerability is reachable when it might not be, and it sometimes misses reachability through reflection or dynamic dispatch. For a regulated environment, treat govulncheck as a powerful first filter and not a complete answer.

How do you verify modules that live on private hosts?

The pattern is GOPRIVATE=*.corp.example.com to exclude internal paths from both the proxy and the checksum database. You then need your own verification story for those modules. A proper internal Git host with signed commits and a CI pipeline that cross-checks hashes against your own internal record gives you the properties the public sumdb gives you for external modules, without leaking internal module paths to Google.

The mistake to avoid is setting GOPRIVATE too broadly. If you set it to *.example.com and you happen to consume a module from a sibling subdomain that does live on a public VCS, you will silently stop verifying that module's hashes. Keep GOPRIVATE scoped as tightly as possible and audit the list when teams add new hosts.

Are there known attacks against the checksum database itself?

No credible attacks against the transparency-log property have been publicly demonstrated. The design is sound, the operational history is clean, and the auditor infrastructure that watches for log inconsistencies has not raised any alarms. What we have seen are availability incidents, where sum.golang.org was slow or briefly unreachable, and the resulting build failures looked like checksum mismatches to developers who did not understand the error messages.

The operational response is not to weaken verification but to build graceful failure behavior into your CI. Cache modules and their hashes aggressively at the proxy layer, and have a documented runbook for sum.golang.org outages that does not involve editing production Go configurations under pressure. Every Go supply chain incident I have worked on that went badly started with someone panicking and setting GOSUMDB=off to unblock a release.

What is the state of module signing on top of the checksum database?

There are ongoing proposals and some experimental tooling for attaching Sigstore-style attestations to Go modules, but in 2026 none of it is standard. The official stance has been that the checksum database provides enough of the relevant properties that signing is not urgent, and there is a reasonable case for that position given how well the current design has held up. Expect this to shift in the next couple of years as the rest of the ecosystem normalizes around signed attestations, but it is not where you should be spending your Go supply chain budget today.

How Safeguard.sh Helps

Safeguard.sh audits your Go build configurations for GOSUMDB=off, over-broad GOPRIVATE scopes, and mismatches between your proxy configuration and your stated trust model. We cross-reference module usage against the Go vulnerability database, track hash consistency across your build environments, and raise a flag when a module you depend on would fail public checksum verification. The goal is to keep the quiet success of Go's supply chain primitives quiet, by catching the configuration mistakes before they become incidents.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.