· via Hacker News – Front Page (native)
Zod 4.6.6 commits carried Ethereum-controlled npm malware loader; registry stayed clean
Malicious commits pushed to the Zod repo added a preinstall loader that fetched follow-on payloads via an Ethereum smart contract; trusted publishing and npm scanning kept it off the registry.
Malicious commits landed in the Zod repository
A commit pushed to colinhacks/zod, surfaced via the Hacker News front page, looked like routine maintenance: under the message "Fix bugs and improve performance" it bumped versions from 4.6.5 to 4.6.6 across zod, @zod/mini and @zod/zod. The diff shows the commit also did three other things. It added a new file, meta.test.mjs, to the zod and mini packages. It inserted a preinstall hook running node meta.test.mjs into the package manifests. And it rewrote the release workflow so that a push to main touching those package. files would publish, replacing a setup where a maintainer had to manually trigger the release and approve a dedicated npm environment.
A loader that asks a blockchain where to fetch its payload
Reading the diff, meta.test.mjs is an obfuscated loader. It cycles through public Ethereum RPC endpoints, issues an eth_call against a hardcoded contract address, and decodes the returned data into a list of hostnames. For each hostname it requests a /loader endpoint; on a hit it writes a base64-delivered payload into a temporary directory, imports a setup script from a data: URL, waits for a completion flag, then deletes the temporary directory.
According to a dev.to write-up citing GitHub's security advisory, the loader pattern uses preinstall and postinstall lifecycle hooks to bootstrap, then downloads and executes remote JavaScript and cleans up after itself. The advisory's indicators include SHA-256 hash 5ed518aaff5aebc729545b8eb223ec31927cd1bfa53169517f09cdbcc9fd5a0b and delivery domain dsakldjklsaj33112[.]com; the diff itself embeds contract address 0xe236330379d0c54aD5b2ef06aC714CEbdd4Ce523.
The blockchain step is the notable design choice. The shipped code carries no second stage, only a pointer: delivery domains can be swapped by updating contract state, the payload never appears in the repository or in registry metadata, and there is no conventional domain to take down.
Nothing malicious reached npm
According to dev.to, no malicious version of Zod was published — the zod changes, and similar commits aimed at standard-schema/standard-schema, never made it to the registry. The same pattern of commits also targeted nubjs/nub, and the one malicious package version actually submitted under the campaign, @nubjs/[email protected], was held by npm's publish-time scanning before it became installable, per GitHub's advisory.
The write-up credits Zod's publishing configuration — trusted publishing via OIDC with no long-lived npm tokens, plus a protected GitHub environment requiring approval — with stopping a repository breach from turning into a registry breach. The maintainer reverted the commit, and a Hacker News commenter noted that the preinstall entry sat at the top level of package. rather than inside the scripts object, which may have kept it from executing at all. That is a formatting accident, not a defense.
Part of a wider pattern
dev.to situates the attempt among earlier incidents: @tanstack/zod-adapter versions 1.166.12 and 1.166.15 shipped malware after an npm account takeover, tied to the "Mini Shai-Hulud" campaign that a GitLab advisory says affected 314 packages, and in 2025 a phished maintainer handed attackers the chalk and debug packages.
Practical steps
The dev.to article's recommendations apply to any TypeScript team:
- Set
ignore-scripts=truein .npmrc and runnpm ci --ignore-scripts, rebuilding only the native modules that need it. - Upgrade to npm 11.16.0 or later, since npm is expected to move dependency install scripts to opt-in execution.
- Treat brand-new releases cautiously; delay adopting a version published minutes ago.
- Make new
"hasInstallScript": trueentries in package-lock. a CI failure that requires human review. - Search node_modules and the lockfile for the delivery domain above; on a hit, rotate every credential on that machine.
- Maintainers should copy Zod's setup: trusted publishing, protected release environments, and 2FA that CI cannot bypass.
One caveat the article raises: disabling scripts does not neutralise malicious bin entries, which run the first time a user invokes the command.
Why it matters
Zod is close to a default dependency in TypeScript, so a malicious release would have spread within hours. This commit had every piece in place — version bump, install hook, workflow change — and the benign outcome depended on several independent controls all holding. An install script runs with the developer's own privileges, with access to SSH keys, cloud credentials, npm tokens and shell environment variables. The Ethereum-based delivery also means auditing package contents cannot tell you what the code will fetch tomorrow. Every control that worked here is available to ordinary maintainers and teams, and most amount to a one-line configuration change.
- #npm
- #typescript
- #security
- #supply-chain
- #zod