Safeguard
Open Source Security

Go module proxy vulnerability trends

A backdoor hid in Go's module proxy for 3+ years, and 63,000+ orphaned packages remain cached. Inside 2025's Go supply chain reckoning.

Safeguard Research Team
Research
6 min read

Security researchers closed out 2025 with a sobering tally: a backdoored Go module that sat undetected in the official module proxy for more than three years, a June 2025 typosquat impersonating a widely used cloud SDK, and a November 2025 ecosystem sweep that turned up more than 63,000 Go packages still cached behind nearly 35,000 deleted GitHub accounts — any one of which could be silently claimed by an attacker and pushed as a "trusted" update. Taken together, the incidents mark 2025 as the year the Go ecosystem's biggest strength — the immutable, always-available module proxy — was also exposed as its most persistent liability.

For a language whose tooling was built around reproducible builds and cryptographic checksums, that's an uncomfortable finding. go.sum, GOSUMDB, and the transparency log at sum.golang.org were designed to guarantee that the code you fetch today is byte-for-byte the code everyone else fetched. What they were never designed to guarantee is that the code was safe in the first place — and 2025 supplied three separate case studies showing how far that gap can be exploited.

The boltdb-go/bolt Backdoor: Three Years Hiding in Plain Cache

The clearest illustration came in February 2025, when researchers at Socket disclosed github.com/boltdb-go/bolt, a typosquat of the popular embedded key-value store github.com/boltdb/bolt. The malicious module had been live on the Go Module Mirror since November 2021 — over three years — quietly offering remote code execution to any project that imported it, with infected hosts checking in to an attacker-controlled command-and-control server. It survived that long not because it was cleverly obfuscated, but because of a structural property of the proxy itself: once proxy.golang.org caches a module version, that version is permanent. Even after the upstream source is taken down, altered, or disavowed, the cached artifact keeps serving builds indefinitely.

Go's maintainers have been explicit that this isn't a bug to be patched — immutability is the point, and it's what makes Go builds reproducible years later. But reproducibility and safety are different properties, and the boltdb-go/bolt case is the clearest evidence yet that attackers understand the distinction better than most build pipelines do.

The Scale Problem: Tens of Thousands of Orphaned Packages

If boltdb-go/bolt was a single, well-executed attack, a broader ecosystem analysis published in November 2025 showed the underlying exposure is far larger than one backdoor. The study identified 34,845 deleted GitHub accounts whose repositories had, at some point, been imported as Go modules — and found that 63,386 packages tied to those now-nonexistent accounts remain fully retrievable from the Go proxy today. In most package ecosystems, a deleted account means a dead dependency. In Go's, thanks to the same caching design that protected boltdb-go/bolt, the package lives on regardless of what happens to its author's account, repository, or organization.

That combination — permanent caching plus abandoned upstream ownership — recreates a well-known npm and PyPI failure mode (repo-jacking and account-takeover republishing) inside an ecosystem that assumed its checksum-and-mirror model had already solved supply chain trust. It hasn't. It has just changed who needs to re-register the abandoned namespace to start serving malicious updates under a name thousands of go.mod files already trust.

Typosquatting Hasn't Gone Anywhere

The third strand of 2025's trend line is the most mundane and, for that reason, the hardest to stamp out: plain typosquatting kept working all year. In June 2025, researchers flagged github.com/qiniiu/qmgo, a near-perfect visual double of the legitimate github.com/qiniu/qmgo MongoDB driver, differing by a single repeated letter. It's the same technique that has worked against npm and PyPI for years, ported into an ecosystem where developers routinely go get a module name from a blog post, a Stack Overflow answer, or a colleague's Slack message without a second look at the org name.

Go's tooling gives defenders real signal here — govulncheck and the Go Vulnerability Database (vuln.go.dev) track known-malicious and known-vulnerable modules, and GOSUMDB will refuse a checksum mismatch — but none of that stops a first-time go get of a name nobody has flagged yet. Detection depends on someone noticing and reporting the typosquat, which is precisely why the boltdb-go/bolt backdoor took three years and the qiniiu/qmgo squat needed independent researchers, not tooling, to surface it.

Why This Adds Up to a Trend, Not a String of Incidents

Three data points don't make a statistical trend on their own, but the pattern across them is consistent enough to name: Go's supply chain risk in 2025 was concentrated less in "vulnerable code" in the traditional CVE sense and more in identity and provenance failures — modules that aren't what their name implies, sourced from accounts or organizations that no longer exist or were never who they claimed to be, then locked into infrastructure explicitly designed never to forget them. That's a different threat model than the one most Go shops are staffed to catch. Scanning for known CVEs in go.sum catches disclosed vulnerabilities in legitimate packages; it does nothing for a backdoor shipped under a name that was never in a CVE database because it was malicious from day one.

The practical fallout for engineering and security teams is threefold. First, go.sum pinning and checksum verification protect build reproducibility but say nothing about whether the pinned version was safe when it was published. Second, the useful half-life of a dependency audit is shrinking — a module that passed review in 2022 can have its upstream ownership silently transferred or abandoned by 2025 with the cached artifact none the wiser. Third, the sheer count of orphaned-but-cached packages (63,000-plus and climbing) means manual review of "who actually owns this dependency" doesn't scale without tooling built for exactly that question.

How Safeguard Helps

This is precisely the blind spot Safeguard is built to close for Go codebases and every other language in the stack. Reachability analysis tells teams whether a flagged or typosquat-adjacent module — like a boltdb-go/bolt or qiniiu/qmgo look-alike — is actually invoked by application code, so security teams can triage the exploitable minority instead of chasing every entry in go.sum. Griffin AI cross-references package names, maintainer and organization history, and behavioral signals to catch typosquats and ownership changes before they're a headline, closing the exact detection gap that let one backdoor persist for three years. Safeguard's SBOM generation and ingestion give teams a live, queryable record of every Go module in production — including ones cached from deleted or transferred GitHub accounts — so "who still depends on this orphaned package" is a search, not an audit project. And when a malicious or high-risk module is confirmed, Safeguard opens an auto-fix pull request pinning or replacing the dependency, turning a discovery that used to take researchers years to surface into a fix that ships in minutes.

Sources:

Never miss an update

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