At 01:12 UTC on October 8, version 0.5.144 of tensorlake, the npm SDK for Tensorlake's AI agent infrastructure, went out carrying a credential-stealing worm from the Shai-Hulud family. This was no typosquat or stolen-token upload. The attacker committed to the project's main branch, the project's own release workflow built the package, and it shipped with a valid npm provenance attestation. Every signature checked out, which is precisely the problem.
A day on main, eleven minutes on npm
The first malicious commit landed on main at 01:20 UTC on October 7, pushed directly with no pull request. Checkmarx counts 13 such commits by 23:41 that night, nine of them wearing GitHub's Verified badge. Tensorlake's fix pull request says a repo-admin account made them through the GitHub web interface, then manually dispatched the npm publish workflow, which signed the result with Sigstore provenance. Nearly 24 hours after that first commit, 0.5.144 reached the registry at 01:12:07 UTC, and Socket flagged it at 01:23:10, 11 minutes later.
The exposure was brief. Tensorlake's advisory puts it at 01:12 to 02:54 UTC, about 1 hour 40 minutes; Checkmarx logs npm's removal nearer 04:15. Either way it was gone the same day, replaced by 0.5.145. The package draws about 12,000 weekly downloads by Socket's count, or about 18,000 by Cloudsmith's, though neither says who pulled the bad version. Tensorlake reports no observed usage of it.
How the attacker got the admin account is unconfirmed. The maintainers' advisory says only that a maintainer account was compromised, which Endor Labs calls the likeliest root cause.
A worm that signs its work and booby-traps the cleanup
A preinstall hook runs lib/setup.mjs, which fetches the Bun runtime and launches an obfuscated 856 KB stealer, so installing the package is enough, import or not; StepSecurity found the loader skips CI, aiming at developer machines. Per Socket, it hunts npm and GitHub tokens, AWS credentials, HashiCorp Vault and Kubernetes secrets, SSH keys, .env files, crypto wallets, and the configuration and MCP files of Claude, Cursor, Kiro, Windsurf and Zed.
Then it spreads. With an npm token it downloads the victim's packages, adds itself, bumps the version and republishes; it even builds Sigstore provenance for them, and per Checkmarx publishes anyway if signing fails. With a GitHub token it commits .claude/settings.json and .vscode/tasks.json into reachable repositories, so the payload runs again when someone opens the project in Claude Code or VS Code. Its command-and-control address resolves through an Ethereum contract queried over about 30 public RPC endpoints, which lets the operators rotate a disposable domain on-chain.
The cruelest part is a dead man's switch. A gh-token-monitor service checks the stolen GitHub token every 60 seconds for up to 24 hours and, if GitHub rejects it, runs rm -rf ~/. The standard reflex, revoke first, pulls the trigger. Tensorlake's advisory says to remove the monitor first, then rotate everything from a clean machine.
Provenance answered the question it was asked
npm's documentation is candid: provenance is a verifiable link from a package to its source code and build instructions, and it "does not guarantee the package has no malicious code." The attestation on 0.5.144 was accurate: the package did come from the repository's main branch and its own workflow. The lie sat upstream of the build, in commits from an account the repository trusted.
The Verified badge has the same limit. GitHub signs commits made in its web interface with its own key and marks them verified, which tells you GitHub recorded the commit for an authenticated session and nothing about whose hands were on the keyboard. A provenance check asks where a package was built. Nothing in this pipeline asked why main had grown an 856 KB obfuscated file.
Thirteen months of Shai-Hulud, and what has changed
The family has form. GitHub learned of the first wave on September 14, 2025, and removed more than 500 packages, a scale CISA echoed in its September 23 alert. The second wave, November 21 to 23, hit 621 npm packages and exposed more than 25,000 GitHub repositories, trading post-install scripts for a preinstall hook and Bun. In August 2026 ChainDrop went through the keyv maintainer to more than 400 packages; Singapore's Cyber Security Agency counted over 1,300 package versions with 2 billion combined monthly downloads. tensorlake's payload shares ChainDrop's file layout and Ethereum resolver.
The registry has hardened since. npm revoked every classic token on December 9, 2025, cut npm login sessions to two hours, capped granular write tokens at 90 days and pointed automation toward OIDC trusted publishing; tokens that bypass 2FA lose direct publishing around January 2027. None of that touched this attack: the attacker needed no token, because the repository's own workflow did the publishing. A consumer-side change would have. npm 12, generally available since July 8, skips dependency install scripts by default unless the project has approved them, so on npm 12 this unapproved hook would not have run.
The defensive lessons are unglamorous. Commit lockfiles, pin exact versions and set a release-age delay (npm's minimumReleaseAge or its pnpm, Yarn and Bun equivalents) so fresh versions must outlive the scanners; this one was flagged in 11 minutes. Keep install scripts off and allowlist the few packages that need them, in CI too, where Tensorlake now runs npm ci --ignore-scripts. Trusted publishing retires long-lived tokens but makes the workflow the boundary, so block direct pushes to main and put a human reviewer on the publish environment, as Tensorlake now does; keep any remaining tokens scoped and short-lived. And treat AI-tool configuration as a credential store: MCP files are on the worm's list, and a pull request touching .claude/ or .vscode/tasks.json deserves the scrutiny of a CI change.
The 30,000-foot read
Provenance did its job. It told the truth about where 0.5.144 was built, and the truth was unhelpful, because the compromise happened one step earlier. That is not an argument against attestation. It is an argument against treating any single green check as a verdict. The registry caught this release in 11 minutes; nothing caught a day of unreviewed commits on main.
What each team controls is the distance between someone else's publish and its own machines. What it does not control is whether the next maintainer account falls. Watch for an explanation of the entry point, for payloads migrating from install hooks into code that runs on import now that npm 12 has closed the easy door, and for AI-tool config directories, which have quietly joined ~/.ssh and ~/.aws on the attacker's shopping list.
Sources: Tensorlake security advisory GHSA-8g63-53c9-65j2 (compromised maintainer account, valid provenance, 01:12 to 02:54 UTC window, no observed usage, remediation order); Tensorlake pull request #1016 (repo-admin account, web-interface commits, manual workflow dispatch, Sigstore signing, hardening steps, 0.5.145); npm Docs (what provenance does and does not guarantee); GitHub Docs (web-interface commits signed and marked verified by GitHub); GitHub blog (first wave, September 14 notification, 500-plus packages removed, post-install scripts); GitHub changelog (classic tokens revoked, two-hour sessions, 90-day cap, trusted publishing recommendation); CISA (September 23, 2025 alert, 500-plus packages); Socket (publish and flag times, weekly downloads, targets, Ethereum resolver, provenance building, ChainDrop link); StepSecurity (first commit time, no pull requests, provenance attestation, CI skip, 856 KB payload, republishing, dead man's switch); Checkmarx (13 commits, nine Verified, 04:15 removal, publish-anyway fallback); Endor Labs (likely root cause, on-chain domain rotation); The Hacker News (.claude and .vscode persistence); Cloudsmith (18,000 weekly downloads); Check Point (second-wave dates, packages, repositories, preinstall hook, Bun); Elastic Security Labs (ChainDrop discovery and package count); Cyber Security Agency of Singapore (ChainDrop package versions and downloads); Socket on npm 12 (install scripts off by default, July 8 release); The Hacker News on npm 12 (2FA-bypass token changes); Socket on minimumReleaseAge (release-age settings in npm, pnpm, Yarn and Bun); Corgea (cites GHSA-rqxj-g25x-4v9v). Corrections to the brief: the maintainers' advisory is GHSA-8g63-53c9-65j2; GHSA-rqxj-g25x-4v9v appears in its references and in Corgea's write-up but could not be opened for this report, so its contents are unverified. The publish workflow ran because the attacker dispatched it manually, per Tensorlake's pull request, not through a routine release. The version was removed the same day, but sources differ on when: 02:54 UTC per Tensorlake, about 04:15 UTC per Checkmarx. Weekly downloads are about 12,000 per Socket and Endor Labs and about 18,000 per Cloudsmith. The payload also carries a home-directory wiper triggered by token revocation and persists through .claude and .vscode files, which the brief omitted. CAVEATs: no source confirms how the admin account was compromised; commit counts differ (StepSecurity describes eight, Checkmarx 13); The Hacker News reports a hardcoded primary C2 domain with the Ethereum contract as a fallback, while Socket reports no hardcoded domain; the absence of observed usage is company-reported; earlier wave sizes come from different organizations counting different things (packages removed, packages infected, package versions) at different times.