Back to Blog

Is Go Safer Than Node.js Against Supply Chain Attacks?

Yes, Go is structurally safer than Node.js against supply chain attacks, mostly because go get does not run install scripts. Here is the case, with sources, and the counterexamples.

Is Go Safer Than Node.js Against Supply Chain Attacks?

Most of the big supply chain attacks of the last two years worked the same way. A developer ran npm install, and a dependency they never picked ran code on their machine before they wrote a single line. npm allows that by design, and it is now walking the decision back. Go never allowed it. This post looks at how much that one difference explains, where Go really is safer, and where it faces the same risks as Node. Every claim has a source.

TL;DR

Go vs Node.js supply chain security at a glance

AspectGo (Golang)Node.js (npm)
Install-time code executionNone. go get/go build run no package scripts.preinstall/install/postinstall run arbitrary code automatically.
When malicious code runsOnly when imported and the function is called.The moment you install, before you write a line.
Integrity guaranteeMerkle-tree checksum transparency log (sum.golang.org), tamper-evident forever.Lockfile hashes plus newer provenance. Historically weaker.
Version resolutionMinimal Version Selection. Upgrades are explicit.Semver ranges (^, ~). A new bad patch can auto-resolve.
Dependency surfaceLarge standard library, fewer direct deps.Tiny-module culture, sprawling transitive trees.
Vulnerability scanninggovulncheck does reachability analysis, so fewer false alarms.npm audit flags the whole tree, which leads to alert fatigue.
Registry modelDecentralized. Modules are source URLs.Central accounts. One phish exposes a whole portfolio.
Still exposed toPhished maintainers, typosquats, proxy caching of malware.All of the above, plus install-script worms.

Go comes out ahead on default behavior and attack surface. A determined attacker who phishes a human maintainer can still get through in either ecosystem.

Why does Go avoid the attack that hits npm hardest?

Go has no install scripts. When you run npm install, every package in the transitive tree can register lifecycle hooks (preinstall, install, postinstall). npm runs them automatically, with your user's privileges, before you have run or even read a single line (npm scripts docs). GitHub has called install scripts the single largest code-execution surface in the npm ecosystem (GitHub Security, 2025).

Go left this out on purpose. It has no build hooks. go get fetches and verifies source, go build compiles it, and neither runs package-defined scripts. A poisoned Go dependency sits there as plain source until your code imports it and calls the malicious function. That window is much narrower and easier to spot than code that runs for everyone on every install.

Here is what each command does:

example.bashbash
# npm: the postinstall hook runs on every install, automatically
$ npm install left-pad
> [email protected] postinstall
> node ./scripts/setup.js   # <- arbitrary code, your privileges, right now

# go: nothing in the package gets to run during fetch or build
$ go get example.com/some/module
go: downloaded example.com/some/module v1.0.0   # source fetched, checksum verified, nothing executed

This difference is why npm v12, shipping in July 2026, blocks install scripts by default, and why pnpm already did the same in v10 (npm scripts docs). The JavaScript tooling is moving toward the behavior Go had from launch.

How bad is the npm supply chain problem, by the numbers?

npm is by far the biggest target. Sonatype identified 454,648 new malicious packages in 2025, which pushed its cumulative blocked total past 1.23 million, a 75% jump year over year. Over 99% of that open-source malware was on npm (Sonatype 11th State of the Software Supply Chain, 2026). Its Q4 2025 malware index put the figure at 99.8% of that quarter's blocked malware.

There is no published count of malicious Go modules at all. Sonatype, OpenSSF, and most vendors don't track Go as a separate ecosystem in their malware indices, because there are too few incidents to index. That gap in the data says a lot on its own.

Where 2025 open-source malware lived (share of new malicious packages, by ecosystem):

EcosystemShare of 2025 open-source malware
npmOver 99%
All others (incl. Go)*Under 1%

*454,648 new malicious packages were identified in 2025. Go is not tracked as a separate ecosystem, because there are too few incidents to index. Source: Sonatype 11th State of the Software Supply Chain, 2026.

What actually happened in the npm worm wave of 2025 and 2026?

A run of self-propagating worms turned a known risk into a constant emergency, and every one of them used install scripts. npm has had high-profile incidents for years. In 2018, event-stream hid a Bitcoin-wallet stealer in a dependency downloaded around 8 million times. In 2021, ua-parser-js shipped cryptominers after an account takeover. But 2025 is when the incidents started coming back to back.

DateIncidentWhat happened
Sep 8, 2025qix phished18 packages hijacked, including chalk and debug. Around 2.6B weekly downloads of exposure.
Sep 2025Shai-HuludFirst npm worm. A postinstall hook harvested credentials and self-injected into roughly 100 more packages per victim.
Nov 24, 2025Shai-Hulud 2.0Moved to preinstall, added a home-directory wipe. Around 796 packages, found in 27% of scanned cloud environments.
Mar 31, 2026axiosDPRK actors social-engineered the maintainer. A postinstall RAT triggered C2 contact in over 12,000 projects.
Jun 2026MiasmaSidestepped npm's install-script block with the "Phantom Gyp" technique, an implicit node-gyp rebuild.

The September 2025 qix compromise started with a convincing 2FA-reset email from the spoofed domain npmjs.help. The attacker took over maintainer Josh Junon's account and published malicious versions of 18 packages. Those included chalk (~300 million downloads per week) and debug (~358 million), for a combined exposure above 2.6 billion weekly downloads. The payload was a browser-side crypto-clipper, and it was live for roughly two hours.

Days later came Shai-Hulud, the first true npm worm. On install, its bundle.js harvested npm, GitHub, AWS, and GCP credentials and ran TruffleHog to scrape secrets. It then used the stolen npm tokens to inject itself into up to about 100 more packages owned by each victim. CISA issued an alert (CISA, 2025). Sonatype attributes 171,740 malicious packages to self-replicating npm campaigns over a few months.

Shai-Hulud 2.0 (November 24, 2025) moved execution to preinstall to reach more machines. It installed the Bun runtime to get around Node-based monitoring and added a destructive fallback that could wipe a home directory. Wiz found affected packages in roughly 27% of the cloud environments it scanned (Wiz, 2025).

In 2026 it became clear that blocking install scripts would not be enough by itself. The axios compromise (March 31, 2026) did not start with a phished password. North Korea-nexus actors (tracked as UNC1069 / Sapphire Sleet) went after the lead maintainer with a fake company, a branded Slack workspace, and a Teams call that planted a RAT on the maintainer's machine. They then published malicious axios versions (100M+ weekly downloads) carrying a postinstall RAT. StepSecurity detected anomalous C2 contact in over 12,000 projects (StepSecurity, 2026). Then Miasma (June 2026) got around npm's upcoming install-script block with the "Phantom Gyp" technique. The package ships a binding.gyp file, and npm's implicit node-gyp rebuild runs the payload without any declared script.

So is Go a silver bullet? Not quite

Go's defaults stop a whole class of attacks, but attackers have still gone after Go a few times. Documented malicious Go modules in 2025 number in the low dozens, spread across a handful of campaigns. Next to npm's hundreds of thousands that is tiny. The most notable case is worth walking through, because it shows how much work an attacker has to do to get past Go's design.

The boltdb-go/bolt backdoor was disclosed in February 2025 but planted back in November 2021. It typosquatted the popular BoltDB module (github.com/boltdb/bolt), which thousands of packages depend on and which was used at Shopify and Heroku, and it carried a command-and-control backdoor. The attacker published the malicious v1.3.1, let the Go Module Mirror cache it, then rewrote the Git tag to point back to clean code. Anyone auditing the repo on GitHub saw clean code, while the proxy kept serving the backdoor. It worked, but only by exploiting an edge case in the caching system. On npm, an install-time hook would have done the job with no such effort (Socket, 2025).

A few other campaigns showed up in 2025. In March there was a wave of hypert and layout typosquats carrying loader malware aimed at financial-sector developers. There were also some disk-wiper modules and an SSH credential stealer. All of these were isolated, and each one needed a developer to type the wrong import path. None of them ran automatically.

When a malicious module is reported, the Go security team removes it from the proxy, which then returns a 403 SECURITY ERROR, and adds it to the Go vulnerability database. For boltdb-go, Google removed the module from both the proxy and GitHub and logged it in the vulnerability database. It also pointed to ongoing work on capability analysis with Capslock and on comparisons with deps.dev. Go's defenses make attacks a lot more expensive, but they don't guarantee safety, and neither does any other ecosystem's.

What makes Go structurally safer?

Besides having no install scripts, Go makes four other design choices that add to the advantage.

Go's checksum database is unusually strong. Your go.sum records SHA-256 hashes of every dependency. sum.golang.org is a Merkle-tree transparency log in the style of Certificate Transparency. It records each module version's hash the first time anyone fetches it and keeps it forever (Go module reference). The go command checks inclusion and consistency proofs before it trusts any code, so a force-pushed Git tag or a tampering proxy fails loudly. Cryptographer Filippo Valsorda, who led Go's security team at Google, has argued that Go has the best package-integrity story of any language ecosystem, because every client in the world resolves a given module version to the same bytes, forever (Filippo Valsorda). The log has one limit. It proves consistency, not that the code is good, and it only helps if someone monitors it.

Minimal Version Selection slows bad releases down. Go builds use the lowest version that satisfies all requirements, and upgrades are explicit (MVS reference). With npm's ^ and ~ ranges, a freshly published malicious patch can end up in a build automatically. In Go, a bad new release doesn't spread downstream until a person deliberately bumps the requirement. The qix and Shai-Hulud worms relied on exactly the auto-upgrade behavior that MVS doesn't do.

govulncheck uses reachability analysis to cut false alarms. Go's official scanner checks the curated vulnerability database at vuln.go.dev and only warns when your code actually calls the vulnerable symbol (govulncheck, Go blog). npm audit flags every vulnerable version anywhere in the tree, whether or not you ever reach it, and developers learn to ignore it.

There is no central account whose takeover exposes a whole portfolio. Go modules are identified by their source URL, so they rely on GitHub's (or GitLab's) account security. On npm, a single taken-over account exposes everything that maintainer owns. That difference is part of why npm worms spread the way they do while Go incidents stay contained.

The larger standard library helps too. HTTP, JSON, crypto, and templating all ship with Go, so a typical project has fewer direct dependencies and fewer maintainers it has to trust. A 2025 study did find that Go's per-dependency amplification (about 4.48x) is close to npm's (about 4.32x), so each Go package doesn't pull in fewer transitive dependencies than an npm one. Go comes out ahead because projects start with fewer direct dependencies, which keeps the set of people you trust smaller.

What Go's defaults don't cover

Go closes the biggest doors automatically. The risks below apply to every ecosystem, Go included, so you have to cover them yourself.

  • A phished maintainer can get past any ecosystem's defenses. If a maintainer's GitHub account is taken over, the attacker can tag a malicious release, and the checksum database records it faithfully because it can't tell good code from bad. An axios-style attack works against every ecosystem, which is why the industry is moving to hardware keys and trusted publishing.
  • You still pick your dependencies by name. Go's checksum verification stops tampering with a module you chose, but it can't stop you from choosing a typosquat. Check the import path against the canonical repo before you add a dependency.
  • Proxy immutability is mostly a feature. The caching that guarantees every build gets identical bytes is also what kept the boltdb-go backdoor reachable after the Git tag was cleaned up. That case was rare, and the Go team's removal process and vulnerability database cover it.
  • The defaults protect install time, not runtime. Go's advantage is that nothing runs during fetch or build. Once you import and call a dependency, it runs with your privileges, the same as in any language. Sandboxing untrusted code at runtime is a separate problem in every ecosystem.
  • Keep the protection on. The one self-inflicted mistake is setting GOSUMDB=off broadly, which turns off the checksum verification described above. Leave it on and scope GOPRIVATE to genuine internal paths only.

How are both ecosystems converging on the same fixes?

Both ecosystems are adopting the same defenses, because in both the weak point is people. After the 2025 wave, GitHub announced mandatory 2FA with FIDO/WebAuthn, short-lived granular tokens, and the deprecation of legacy classic tokens. It is also pushing trusted publishing via OIDC for cryptographic build provenance (GitHub Security, 2025). npm v12 (July 2026) blocks install scripts by default and adds a min-release-age cooldown, so a package that is only live for two hours never reaches you.

These changes help. But axios showed where they stop working. No token policy stops a maintainer whose laptop is running a RAT. Only hardware FIDO2 keys combined with provenance-verified, cooldown-gated installs would have. Both communities are learning that attackers go after the maintainer more than the tooling. Go still has an edge there. Even when a maintainer is compromised, less damage follows, because nothing runs on install.

What should you do right now?

The steps depend on your stack.

If you write Go:

  1. Never set GOSUMDB=off or GONOSUMCHECK broadly. Scope GOPRIVATE narrowly to genuine internal paths.
  2. Commit go.sum and build with -mod=readonly.
  3. Run govulncheck ./... in CI as a reachability-aware gate.
  4. Vet new dependencies for typosquats. Verify import paths against the canonical repo before you add them.
  5. Monitor critical dependencies for new releases with Socket or deps.dev.

If you write Node:

  1. Upgrade to npm 11.16.0+ and set ignore-scripts=true, with an allowlist (such as @lavamoat/allow-scripts) for the few packages that truly need scripts.
  2. Use npm ci with a frozen lockfile, pin exact versions, and set a 3 to 7 day min-release-age cooldown so two-hour compromises never reach you.
  3. Adopt trusted publishing (OIDC) and hardware FIDO2 keys. Do not rely on TOTP for publishing.
  4. Run real software composition analysis (Socket, Snyk) with behavioral detection, not just npm audit.
  5. Defensively register your internal package names publicly to block dependency confusion.

FAQ

Is Go really safer than Node.js for supply chain security?

Yes, structurally. The main reason is that go get and go build run no install-time scripts, which removes the preinstall/postinstall vector behind nearly every major npm worm of 2025 and 2026. Over 99% of 2025 open-source malware appeared on npm (Sonatype, 2026). Go is safer, but it is not immune.

What is the single biggest difference between Go and npm security?

Install-time code execution. On npm install, npm automatically runs arbitrary package scripts with your privileges, for every package in the tree. Go has no build hooks at all, so a malicious dependency does nothing until your code imports it and calls it. That is why npm v12 now blocks install scripts by default, which is how Go has always behaved.

Has Go ever had a supply chain attack?

Yes. The boltdb-go backdoor typosquatted BoltDB and served a remote-access backdoor from Go's module cache for three years (Socket, 2025). A 2025 hypert/layout campaign shipped at least seven typosquats with loader malware. These incidents are real but rare, and malicious modules are removed from the proxy once reported.

What is the Go checksum database and why does it matter?

sum.golang.org is a Merkle-tree transparency log. It permanently records the hash of every module version the first time that version is seen. The go command verifies these proofs before trusting code, so tampering or a rewritten Git tag fails loudly (Go module reference). Every client gets identical bytes for a given version, which is the strongest integrity guarantee in mainstream package management.

Does blocking npm install scripts fix the problem?

It helps a lot, but it doesn't fix everything. The axios attack used a postinstall RAT after social-engineering the maintainer, and the Miasma campaign got around the script block through an implicit node-gyp rebuild. Blocking scripts together with hardware FIDO2 keys, a release cooldown, and provenance verification closes most of the gap. A phished maintainer can still get past any single control.

Should I switch from Node to Go for security alone?

Security counts in Go's favor, but most teams choose a language for everything it brings: concurrency, hiring, ecosystem, and how fast they can ship. Go is a strong backend language and also the structurally safer one against supply chain attacks. If you are already considering it, the safer defaults are one more reason to learn it.

Sources

Primary sources cited in this post (last verified June 29, 2026):

Write Go like a senior engineer

Interactive lessons in your browser. The first ones are free.

Try a free lessonOr create a free account