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:
| Repository | Time (UTC) | npm outcome |
|---|---|---|
colinhacks/zod | 11:56:52 | Never entered npm publishing |
standard-schema/standard-schema | 12:37:19 | Never entered npm publishing |
nubjs/nub | 12:54:48 and 13:00:18 | 0.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
preinstallscript, 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/nub0.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
- 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.
- 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
maincould trigger a publish. - 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.
- 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.
- Flag install hooks that fetch from the network. A dependency whose
preinstallreaches 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.