Safeguard
Incident Analysis•

Zod, nub and Standard Schema: Malicious Commits npm Blocked Before Install

On 21 September 2026 a stolen git push credential put an Ethereum-based loader into three repositories. Only nub reached npm's pipeline, and publish-time scanning blocked it.

Safeguard Security Team
6 min read

On 21 September 2026, between 11:56 and 13:00 UTC, commits titled "Fix bugs and improve performance" added a remote loader to three public repositories: colinhacks/zod, standard-schema/standard-schema and nubjs/nub. Each hooked the loader into an install script. Only @nubjs/nub@0.9.4 made it into npm's publishing pipeline, and npm's publish-time scanning blocked it at 13:09 UTC before it became installable. Zod's maintainer later said a git push credential had been compromised.

What's affected

GitHub's advisory, posted in the npm community discussions on 21 September, lists the commits:

RepositoryTime (UTC)npm outcome
colinhacks/zod11:56:52Never entered npm publishing
standard-schema/standard-schema12:37:19Never entered npm publishing
nubjs/nub12:54:48 and 13:00:180.9.4 blocked by npm scanning

Files involved include npm/nub/preinstall.js, packages/zod/meta.test.mjs, packages/mini/meta.test.mjs, meta.mjs and packages/utils/meta.mjs. The names are chosen to look like test or metadata files.

The loader, per the advisory, queries public Ethereum RPC endpoints, reads a fixed smart contract to find its delivery address, downloads JavaScript from that address and runs it with the permissions of the install process, then deletes its temporary files. Because the address lives in a contract, the payload can change without any new commit or release. The response captured during analysis was inert placeholder output.

What this means for your dependency tree:

  • Zod on npm is not affected. The registry shows Zod 4.6.5 published on 13 September, then 4.6.6 on 11 October and 4.6.7 on 12 October. None of them declares a preinstall script, and all carry provenance attestations. The malicious commit had bumped the repository's version to 4.6.6 in September, which is why the later legitimate 4.6.6 release prompted questions.
  • @nubjs/nub 0.9.4 does not exist on npm. The registry jumps from 0.9.3 to 0.9.5.
  • Standard Schema packages were never published from the malicious commit.

The exposure is for anyone who cloned one of these repositories on 21 September and ran an install from source before the reverts.

How to check if you're exposed

If you build any of these projects from git, check whether an old clone still contains the commits. Zod's maintainer says its history was later cleaned up, so a fresh clone may not have them:

git -C zod branch -a --contains d821685ea6 2>/dev/null
git -C standard-schema branch -a --contains 92703a50d3 2>/dev/null
git -C nub branch -a --contains da01135c91 2>/dev/null
git log --all --oneline --since=2026-09-20 --until=2026-09-23 --grep='Fix bugs and improve performance'

On developer machines and build hosts, search DNS, proxy and EDR logs for the delivery domain and loader path:

dsakldjklsaj33112.com
https://dsakldjklsaj33112.com/loader

The advisory also lists the SHA-256 of preinstall.js as 5ed518aaff5aebc729545b8eb223ec31927cd1bfa53169517f09cdbcc9fd5a0b. Connections to public Ethereum RPC hosts such as eth.llamarpc.com or cloudflare-eth.com from a build process are only meaningful alongside the other indicators, since they are shared infrastructure.

For consumers installing from npm, confirm what you resolve:

npm ls zod @standard-schema/spec @nubjs/nub

What to do now

  1. If you built from source on 21 September, check the logs above. If the loader ran, treat the machine as compromised and rotate the credentials it held.
  2. Protect the branch, not only the registry account. Require pull request review for the default branch so a stolen push credential cannot land code directly. Zod's attacker also edited the release workflow so a push to main could trigger a publish.
  3. Separate push access from release authority. Publish from protected tags or a protected environment with required reviewers. The Zod maintainer says his packages now use environment-scoped staged publishing that requires 2FA.
  4. Use short-lived, scoped git credentials. Fine-grained tokens with expiry, or SSH keys protected by hardware or a passphrase, limit what a stolen credential can do and for how long.
  5. Flag install hooks that fetch from the network. A dependency whose preinstall reaches out to a blockchain RPC endpoint is not doing anything a library needs.

Why it matters

This is the good outcome, and it is worth understanding why. npm's publish-time scanning stopped the one release that reached it. Zod's trusted publishing flow, by the maintainer's account, was not bypassed, and the bad Zod commit never triggered a publish at all.

But the attack itself worked. A single git credential let someone push to three widely used projects within an hour. The next attempt may target a project without registry-side scanning, or a payload the scanner doesn't flag. Branch protection and review on workflow changes are the controls that would have stopped it at the first step.

The blockchain-hosted address is also worth noting. Taking down a domain doesn't stop a loader that asks a smart contract where to go next. Detection has to look at behaviour: install scripts making network calls and running downloaded code.

Try it yourself

Pick a repository you maintain and answer three questions. Can someone with push access but no reviewer land a commit on the default branch? Can a push to that branch, without a tag or approval, publish a release? Who can edit files under .github/workflows/? If any answer is "yes" or "anyone with write access", that is the gap this attacker used.

Click through it at your own pace, or open it full screen.

Quick check

Did a malicious Zod version reach npm?

No. GitHub's advisory says the Zod and Standard Schema changes never entered npm publishing. Only @nubjs/nub 0.9.4 did, and npm blocked it before it was installable.

Why does the loader read an Ethereum smart contract?

The contract holds the delivery address, so the attacker can change the payload location without a new commit or release, and a domain takedown alone doesn't stop it.

Who was actually at risk?

People who cloned one of the three repositories on 21 September and ran an install from source before the malicious commits were reverted.

Sources

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.