Back Original

Inspecting the Source of Go Modules

Go has indisputably the best package integrity story of any programming language ecosystem. The Go Checksum Database guarantees that every Go client in the world is using the same source for a given Go module and version, forever.

It works despite the decentralized nature of Go modules, which can be fetched directly from their origin based on the import path. (For example, you can fetch v1.2.3 of github.com/example/mod by cloning the git repository and exporting the v1.2.3 tag. GOPROXY=direct forces this.1)

The Checksum Database stores the cryptographic hash of a module version the first time it is used across the ecosystem, and then provides that same checksum to every Go client going forward. If e.g. a git tag were force-pushed or a code host were to try to serve targeted versions to some clients, the go tool would notice the mismatch and fail the fetch.

This is vastly more practical than requiring module authors to manage keys, but provides comparable security, because the author themselves can verify the checksum in the Checksum Database matches the one they developed. Moreover, the Checksum Database is a transparency log, which prevents even the database operator (i.e. Google) from falsifying or hiding entries.

However, any time we read code directly from the code host we introduce a weak link in this chain. For example, there is no guarantee that the code displayed at https://github.com/example/mod/blob/v1.2.3/exp.go is the actual contents of exp.go from v1.2.3 of module github.com/example/mod: GitHub allows force-pushing git tags and even built its recommended GitHub Actions workflows on top of mutable tags.

Last year this was taken advantage of to make a classic typosquatting attack harder to identify. A fake BoltDB module was published with malicious code, and then innocent code was force-pushed to GitHub. Some commenters described this as exploiting the Go Modules Mirror’s cache, but it is better understood as exploiting the natural lack of verification in the GitHub web interface, which doesn’t show the authentic (and in this case malicious) source of a module version, as used by actual Go tooling.

The solution when reviewing modules locally is to use a command like

cd $(go mod download -json filippo.io/age@v1.3.1 | jq -r .Dir)

to fetch the correct source.2 We are also working on a go mod verify -tag command to verify the contents of a local git repository against the Go Checksum Database, which can also be used by module authors to check that the contents of the Checksum Database are correct.

However, pkg.go.dev still links to unverified code hosts, and clicking on pkg.go.dev source links is very convenient.

Russ Cox made a simple service to view the source of a Go module at go-mod-viewer.appspot.com.

pkg.geomys.dev is a new similar service with optional syntax highlighting, line and line range linking, multiple fonts, automatic dark mode, and a file tree and module versions browser.

You can use it manually by replacing go.dev with geomys.dev in any pkg.go.dev URL, or you can install the companion browser extension for Chrome and Firefox, which replaces links to code hosts in pkg.go.dev pages with links to pkg.geomys.dev.

Available in the Chrome Web Store

Get the Add-on for Firefox

The service works by making HTTP Range requests directly to the module version’s zip file, and decompressing the file in the browser, without having to fetch the whole archive. Once proxy.golang.org fixes their CORS configuration it will work without any Geomys backend.

Currently, it trusts the Google Modules Proxy to serve the correct zip files, without checking the transparency log proof. I plan to implement optional proof checking once proxy.golang.org CORS is fixed, including third-party gossip. Unfortunately, checking the proof does require fetching the whole module version’s zip archive to compute the dirhash, which is included in the Checksum Database (and in go.sum).

For updates, follow me on Bluesky at @filippo.abyssdomain.expert or on Mastodon at @filippo@abyssdomain.expert.

The picture

I recently went to Paris and found the Tour Eiffel elevator to be more fascinating than the tower itself. Whatever that says about me.

A shot of the Tour Eiffel from the inside, looking up. A web of metal with the yellow elevator and its rails in the middle.

My work is made possible by Geomys, an organization of professional Go maintainers, which is funded by Ava Labs, Teleport, Tailscale, and Sentry. Through our retainer contracts they ensure the sustainability and reliability of our open source maintenance work and get a direct line to my expertise and that of the other Geomys maintainers. (Learn more in the Geomys announcement.) Here are a few words from some of them!

Teleport — For the past five years, attacks and compromises have been shifting from traditional malware and security breaches to identifying and compromising valid user accounts and credentials with social engineering, credential theft, or phishing. Teleport Identity is designed to eliminate weak access patterns through access monitoring, minimize attack surface with access requests, and purge unused permissions via mandatory access reviews.

Ava Labs — We at Ava Labs, maintainer of AvalancheGo (the most widely used client for interacting with the Avalanche Network), believe the sustainable maintenance and development of open source cryptographic protocols is critical to the broad adoption of blockchain technology. We are proud to support this necessary and impactful work through our ongoing sponsorship of Filippo and his team.