Skip to content

BuildNot yet confirmed elsewhere1 publisher2 min readPublished

Malicious commits hit Zod, nub and standard-schema repos, but no malicious version reached npm: Zod's release setup held and npm's scanner caught the nub version

Malicious commits landed in three GitHub repos, including Zod, yet npm's scanner held the only bad release submitted, @nubjs/nub@0.9.4. That outcome says little about whether a consuming team's own lockfile and install settings would have held.

The Engineer · Build desk

How we use AISend a correction

Zod's release flow and npm's scanner kept malware off npm What held this attack back, per the dev.to write-up. Not charted: the only count, 314 packages, belongs to a separate campaign.

Map of five entries. A misplaced preinstall entry may have kept the hook from running. Zod's release flow kept the repo compromise off the registry. npm's scanner held the nub release before it was installable. A related campaign hit 314 packages, per GitLab. npm will move to opt-in scripts.

Zod's release flow and npm's scanner kept malware off npm
WhoHowKindClaim
Attacker's package.jsonPreinstall entry sat at the root, not under scripts, which a commenter said may have kept it from running at allconstraint21
Zod maintainersTrusted publishing plus a dedicated GitHub environment kept the repo compromise from becoming a registry compromisecapability18
npm publish-time scannerHeld the one malicious version submitted, the nub release, before it was installable, per GitHub's advisorydecision3
Mini Shai-Hulud campaignTied to the earlier @tanstack/zod-adapter account takeover; GitLab's advisory says it hit 314 packagesprecedent8
npm (per GitHub)Will move to opt-in script execution for dependencies; the write-up says to prepare and not wait for the default to flipdecision23

What happened

  • The payload was a remote loader that gets the download location for its next stage from an Ethereum smart contract.
  • The malicious files sat in test-looking paths, packages/zod/meta.test.mjs and packages/mini/meta.test.mjs.
  • A Hacker News commenter noted the preinstall entry sat at the root of package.json instead of under scripts, possibly stopping it from running, and the maintainer reverted the commit.

Why it matters

  • exposure A hook that does run executes as the installing user, with reach to ~/.ssh, ~/.aws/credentials, ~/.npmrc tokens and every environment variable in the shell.
  • decision Teams must choose between turning dependency install scripts off now and waiting for npm's announced opt-in default; the write-up says to upgrade to npm 11.16.0 or later and not wait.
  • precedent The write-up groups this with the @tanstack/zod-adapter takeover, tied to a campaign GitLab says hit 314 packages, and the 2025 chalk and debug phishing as one stolen-credential pattern.

The write-up's headline says a lockfile did not save anyone [14]. On the facts it reports, the lockfile was never in play. The zod and standard-schema changes were never published [4], so no lockfile could have pinned a malicious version of either [15].

What stopped the compromise was narrower than the three layers the write-up lists [22]. Of the three repos [1], only one produced a submitted version [16], and npm's scanner held that one [3]. For Zod, the write-up credits the maintainer's release setup: OIDC trusted publishing with no long-lived npm tokens, a dedicated GitHub environment with required approval, and 2FA that cannot be bypassed from CI [19]. A commit to the repo did not become a release [18]. The write-up does not say whether nub had comparable publishing controls.

The write-up is of two minds about all this. It calls the ending luck [14], then says "Zod's maintainers did the right things and it worked." [20] Both can hold, because the stop differs by repo: the release flow for Zod [18], the scanner for nub [3]. In our view the weakest layer is the install path. It rests on a single commenter's account, and the author tells readers to check GitHub issue #6658 and the advisory for the authoritative timeline [24].

On the consuming side, the loader's first step needs the preinstall and postinstall hooks [6]. The write-up's lead control is one line in .npmrc, ignore-scripts=true, followed by an explicit rebuild of the few packages that need a build step, such as sharp, bcrypt and sqlite3 [10]. That setting does not cover a malicious bin entry, which runs when the command is invoked. The write-up says the Bitwarden incident did exactly that [11]. It also pairs the setting with a minimum release age, on the logic that fresh versions are where compromises live [13].

The payload is stored outside both the repo and the registry, and updating a contract is enough for the attacker to replace it [7]. The write-up's quick check greps node_modules and package-lock.json for the delivery domain dsakldjklsaj33112[.]com and says to rotate every credential on the machine if it matches [12]. A clean grep clears one delivery location, and the location is the part the attacker can change [17].

What to watch

  • GitHub issue #6658 and the advisory timeline, which settle whether the root-level preinstall entry would have run.
  • Whether the advisory explains how the @nubjs/nub@0.9.4 submission was made and what publishing controls nub had.
  • Which npm release flips dependency script execution to opt-in; the write-up points to 11.16.0 or later as preparation.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence50
Adoption
Insufficient
Hype gap+25
Incentives
Insufficient
Confidence55
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    Malicious commits were pushed to colinhacks/zod on GitHub, and the same pattern hit nubjs/nub and standard-schema/standard-schema.

    ReportedSupportedSource: dev.to write-upView cited source
  2. [2]

    The payload was a remote loader that asks an Ethereum smart contract where to download its next stage.

    ReportedSupportedSource: dev.to write-upView cited source
  3. [3]

    No malicious Zod version reached npm; per GitHub's advisory, npm's publish-time scanning held the one malicious version that was submitted, @nubjs/nub@0.9.4, before it was installable.

    ReportedSupportedSource: dev.to write-up, citing GitHub's advisoryView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · October 12, 2026

    Zod Got Backdoored. Your Lockfile Didn't Save You, Luck Did.

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

Loading related stories