Don't Go with the flaw
research

Go Supply Chain Security in Brief

TL;DR: Go’s decentralized module system and checksum verification reduce some supply chain risks familiar from npm and other ecosystems. They do not establish whether a dependency is trustworthy. Misleading module paths, changes in repository ownership, and differences between cached modules and visible source code remain relevant attack vectors.


A different distribution model, not an absence of risk

Go does not rely on a single registry where publishers claim short package names. Instead, module paths identify a source repository or a domain controlled by the publisher. This makes dependency confusion based solely on matching a private package’s short name less straightforward. Go also has no npm-style dependency installation scripts.

Go remains exposed to typosquatting, compromised maintainers, and malicious updates. Its distribution model also introduces a distinctive risk: the Go proxy can deliver content different from the source currently visible upstream. Centralized registries avoid this repository-to-proxy resolution mechanism, although their artifacts can also differ from associated source repositories.

This article summarizes Don’t Go with the flaw, using documented attacks to explain the risks.

Dazio by Boost Security helps protect your Go projects with free, automated checks for known-malicious dependencies.

What Go verifies

By default, the Go toolchain downloads public modules through proxy.golang.org and authenticates their checksums using sum.golang.org. The proxy caches module versions, and the checksum database provides an auditable record of their content hashes.

These mechanisms help prevent a previously recorded version from being silently replaced. They do not establish whether its original content was malicious: a valid checksum establishes consistency, not trustworthiness.

Downloading a module does not normally execute its Go code. Malicious code can run when an application or test binary executes, through package initialization (init() functions and global variable initializers) or ordinary function calls. go run and go test therefore expose execution paths that downloading alone does not. Ordinary go build and go install do not run a compiled dependency’s initialization code. This differs from the installation-time execution mechanisms available through pip and npm.

Builds can still invoke native tools through cgo (import "C"). Go restricts compiler flags to prevent arbitrary code execution during a build. Allowing unsafe flags through CGO_CFLAGS_ALLOW, such as a flag that loads a compiler plugin, can weaken that protection.

Familiar attacks against Go modules

Typosquatting and impersonation. An attacker can publish a working copy of a legitimate module under a similar-looking path, with added malicious behavior. In June 2025, GitLab reported github.com/qiniiu/qmgo and github.com/qiiniu/qmgo, which imitated github.com/qiniu/qmgo. Their payload ran from NewClient, a function applications would normally call, and downloaded malware that provided remote access. Including the hosting account in the module path limits collisions between unrelated publishers, but attackers can imitate that account name as well as the module name.

Impersonation does not require a spelling mistake. OpenSourceMalware’s Go listings include gocommunity.io/orderedbtree and gogets.dev/btreex. In its September 2026 Graphalgo investigation, Aikido documented malware in both modules, along with websites presented as Go package ecosystems. The latter module used a specific input condition to trigger its payload, illustrating why a successful test run is not evidence that a dependency is benign.

Repository and domain takeover. Module identity depends partly on continued control of its hosting namespace. If an abandoned account or repository name can be reclaimed, an attacker may publish new versions at an existing module path: repojacking. An expired custom domain can similarly give an attacker control over module resolution. Previously authenticated versions are not thereby rewritten, but future version selection can lead to attacker-controlled code. Gobelin helps identify GitHub accounts exposed to repojacking, flagging takeover risk rather than proven compromise.

Dependency confusion. Full module paths make simple name collisions insufficient. However, a private module path that resolves publicly to attacker-controlled infrastructure can still introduce unintended code. GOPRIVATE keeps matching paths away from public proxies and the public checksum database by default; it does not authenticate whoever controls the destination. Private domain ownership, DNS, and network configuration remain part of the security boundary.

When the proxy and repository disagree

The proxy preserves cached module content even when the upstream repository changes. An attacker can exploit this by publishing a malicious version, causing it to be cached, and then moving the Git tag to clean code. Someone reviewing that tag on GitHub may see different content from what Go downloads.

This was not merely a proposed technique. In February 2025, Socket reported that github.com/boltdb-go/bolt, an imitation of github.com/boltdb/bolt, used proxy caching to preserve a backdoored version while presenting cleaned-up source upstream.

Pseudo-versions offer a related possibility. These versions identify a particular commit rather than a release tag. Once cached, a malicious commit can remain downloadable after it disappears from the repository’s visible branch history. A dependency update or a root-level replace directive can then direct a project to that artifact. Staging malicious tags or commits requires the ability to publish them in the referenced repository; redirecting a consumer to them requires a separate dependency change.

Protect your project

  1. Get the module path from the project’s official documentation. Copy it rather than typing it from memory. Before adding a dependency, double-check the account and repository name, not just the package name.

  2. Automate known-malware checks. Dazio by Boost Security automatically checks Go dependencies in your projects and local module cache for known malware. With install protection enabled, it can also block downloads of known-malicious modules routed through its Go proxy. It is free to use.

  3. Pause when something is flagged. Do not run the affected application or its tests. Share the module path, version, and warning with your security team or project maintainer. If you have already run the application or its tests, let them know so they can help assess your exposure and replace any credentials at risk.

A clean scan is not a guarantee that a dependency is safe. If you use private modules, ask whoever manages your Go setup to confirm that they resolve through your organization’s approved sources.