NEWS
Shai-Hulud npm Worm Left Cloud Keys After Cleanup
Shai-Hulud dumped secrets into 25,000 GitHub repos, then lingered in cloud keys, caches and Actions after npm pulled the packages.
Unit 42 counted over 25,000 malicious GitHub repositories tied to the November 2025 Shai-Hulud 2.0 npm worm. The payload ran in the preinstall step, stole cloud and GitHub secrets, and dumped them in public repos labeled “Sha1-Hulud: The Second Coming.”
Microsoft later told defenders to rotate credentials again when Mini Shai-Hulud returned in 2026. Pulling tainted packages off the registry left AWS, Azure and Google Cloud keys sitting where the worm had already copied them.
A Preinstall Script Fired on Every Build
Unit 42 researchers Justin Moore and colleagues traced the first wave to phishing mail that spoofed npm and asked developers to “update” multi-factor login options. Once a maintainer token was in hand, the actor published poisoned package versions that ran a post-install script, scraped.npmrc files and environment variables, and hunted GitHub personal access tokens plus API keys for AWS, Google Cloud and Microsoft Azure.
The November campaign moved that hook earlier. A file named setup_bun.js pretended to be a Bun installer, then launched bun_environment.js, an obfuscated payload over 10 MB. Because the script ran in preinstall, it executed on developer laptops and on CI runners before tests or most scanners ever saw the tree. Unit 42 wrote that this removed the need for a person to click through the install and also skipped static checks that only run later in a build.
If the malware could not steal a token, create a GitHub repo or open an exfil path, it tried to wipe the user’s home directory by overwriting and deleting writable files. Microsoft Defender for Containers later alerted on suspicious use of the shred command against hidden files during that sabotage step. In some of the new repos, commits appeared under the name Linus Torvalds, which Microsoft flagged as impersonation and a reason to require signed commits.
Assume that any secret present on a developer’s machine may have been compromised.
Justin Moore, Unit 42, Palo Alto Networks technical report
Stolen secrets went to public GitHub repositories. The first wave used a repo named Shai-Hulud. The second used random 18-character names and the description “Sha1-Hulud: The Second Coming,” plus a workflow file named discussion.yaml that registered the box as a self-hosted runner.
Why Unpublishing Packages Did Not End It
CISA’s September 23, 2025 alert told organizations to review lockfiles, search artifact caches and rotate all developer credentials. npm and GitHub could yank a malicious version in hours. That did not recall a cloud key that had already been copied into a public dump, a private mirror or a runner that was still online.
Wiz Research later showed how that gap looked in production. Private registries and local caches kept serving copies that the public registry had already revoked. An OpenVSX editor extension stayed malicious on disk because the registry had rolled back to an older version, so IDEs never auto-updated. A month after containment, platform tokens were mostly dead and cloud keys were not.
That is why password resets on npm and GitHub were necessary and still incomplete. The worm’s useful output was a pile of long-lived cloud, SaaS and AI keys, plus a runner that could take new orders through GitHub discussions.
Zapier, PostHog and 25,000 Public Dumps
Unit 42’s November 25, 2025 update put the second wave at over 25,000 malicious GitHub repositories across about 350 unique users. Microsoft named maintainer accounts at Zapier, PostHog and Postman among those abused to publish the trojanized packages.
PostHog’s own incident note says malicious versions of its JavaScript SDKs, including posthog-node 4.18.1, 5.13.3 and 5.11.3, went up at 4:11 AM UTC on November 24, 2025. By 9:30 AM UTC the company said it had deleted those versions and revoked the publishing tokens. The install script had already run TruffleHog against the environment, opened a public GitHub repo and pushed whatever it found.
Replit chief executive Amjad Masad wrote that anyone could watch the theft land, live: “you can see a list of people getting pwned in realtime by refreshing this GitHub search page.” The dumps were not hidden in a dark web drop. They were ordinary public repositories, which meant other actors could scrape the same secrets the worm had just stolen.
THE SHAI-HULUD WAVES
| Wave | When | What was recorded |
|---|---|---|
| Shai-Hulud | September 2025 | CISA: over 500 npm packages |
| Shai-Hulud 2.0 | November 2025 | Unit 42: over 25,000 GitHub repos, about 350 users |
| Mini Shai-Hulud | May 2026 | Microsoft: 170-plus npm packages, 2 PyPI packages, 404 versions |
| Mini variant | August 2026 | Microsoft: keyv, cache-manager and related preinstall droppers |
Wiz’s first-day capture lined up with Unit 42’s repo count. GHArchive logged 13,686 new secret-dump repositories on November 24, 2025, a feed Wiz treats as about half of GitHub activity.
September 2025 Opened the Door
CISA described a self-replicating worm on npmjs.com that had already hit over 500 packages by September 23, 2025. After the first login, the actor scanned for GitHub tokens and cloud API keys, sent them to an actor-controlled endpoint, uploaded a public Shai-Hulud repo through the GitHub repos API, then authenticated back to npm as the victim and published more poisoned versions. CISA told teams to pin dependencies to known-safe releases produced before September 16, 2025, block webhook.site, and require phishing-resistant MFA on GitHub and npm.
Unit 42 assessed with moderate confidence that an LLM helped write the original malicious bash, based on comments and emojis in the script. The September payload still needed a post-install hook. The November rewrite did not.
HOW THE CAMPAIGN KEPT RETURNING
- September 16, 2025: CISA’s later pin date; packages published after this day were treated as unsafe until proven clean.
- September 23, 2025: CISA publishes its npm worm alert and orders credential rotation.
- November 21 to 23, 2025: Wiz and Aikido place the trojanized 2.0 packages on the registry.
- November 24, 2025: Secret-dump repos spike; PostHog and other maintainers scramble the same morning.
- December 9, 2025: Microsoft publishes detection guidance and tells customers to isolate CI agents and rotate vault access.
- December 24, 2025: AsyncAPI ships a clean OpenVSX 1.1.0 build after Wiz traces leftover infections to the 1.0.1 editor extension.
- May 11, 2026: Microsoft tracks Mini Shai-Hulud across npm and PyPI in one operation.
- August 4, 2026: Microsoft Threat Intelligence posts a fresh Mini wave hitting keyv and cache packages.
The August alert is the one most teams still have pinned in Slack.
Microsoft Threat Intelligence is tracking active Mini Shai-Hulud npm supply chain attacks in which a threat actor compromised trusted maintainer accounts to distribute credential-stealing malware.
Compromised packages (confirmed malicious) include:
– keyv@6.0.0
-… pic.twitter.com/x6GJZiNRZT— Microsoft Threat Intelligence (@MsftSecIntel) August 4, 2026
Cached Copies Outlived the Registry Cleanup
Wiz’s December 30, 2025 follow-up is the clearest picture of what “cleaned up on npm” actually meant. After the public crash in new infections, the rate settled at about 100 to 200 new compromised repositories every day from November 25 through December 24, 2025. Wiz’s dataset covered more than 29,000 leaked repositories and more than 12,000 unique compromised machines, and the firm said the incident had touched more than one third of the Fortune 100.
About 5 percent of those lingering hits came from private registries and local caches. Mirrors such as Nexus or Artifactory had already pulled the bad tarball. When npm unpublished it, the internal copy stayed. CI jobs that run with –offline or –prefer-offline never asked the public registry again.
More than 90 percent of the long tail traced to a single OpenVSX extension, asyncapi-preview 1.0.1. OpenVSX pulled it on November 26, 2025, then rolled the listing back to 1.0.0, so installed copies of 1.0.1 had no newer version to replace them. Victim logs showed a Pacote git pointer at commit 2efa4dff59bc3d3cecdf897ccf178f99b115d63d on asyncapi/cli, the malicious fork from the original wave. AsyncAPI published a clean 1.1.0 on December 24, 2025. Wiz said daily new dump repos then fell to a handful by December 29.
WHERE THE WORM HID AFTER NPM
- Daily drip: About 100 to 200 new secret-dump repositories each day from November 25 to December 24, 2025.
- Editor hang: More than 90 percent of long-tail infections traced to asyncapi-preview 1.0.1.
- Internal mirrors: About 5 percent kept serving revoked tarballs from private caches.
- Victim set: More than 12,000 unique compromised machines in Wiz’s later tally.
A freeze on dependency updates, the joke that went around when the dumps were public, would not have saved a runner that already had the bad tarball in cache.
About Half the Cloud Keys Were Still Live
On December 1, 2025, Wiz still saw most leaked npm tokens working. By December 28, after GitHub and npm mass-revoked platform credentials, that picture had flipped for the registry and for GitHub, and it had not flipped for cloud.
UNROTATED SECRETS ON DECEMBER 28, 2025
| Credential type | Revocation rate (Wiz) | What was still open |
|---|---|---|
| GitHub tokens | Over 95 percent | Dozens still valid |
| npm tokens | Over 90 percent | Roughly a dozen still valid |
| Cloud credentials | About 50 percent | Hundreds of long-lived keys |
| AI API keys | Low | Over 200 valid keys (OpenAI, Gemini) |
| SaaS and dev tools | Low | Dozens of valid keys (Slack, Cloudflare, Airtable) |
Wiz’s line on cloud access is the one that should have governed incident close-out: hundreds of long-lived keys remain valid. Teams rotated what the platforms forced them to rotate. They were slower on AWS, GCP and Azure keys that never expire on their own, and slower still on Chrome Web Store refresh tokens, Slack bots and model APIs.
Trust Wallet reported $7 million stolen after a malicious browser-extension build, v2.68, on December 25, 2025. Wiz found a GitHub token with admin:enterprise scope over the trustwallet organization, plus Chrome Web Store client secrets taken from GitHub Actions, inside the Shai-Hulud dumps. After Wiz published, Trust Wallet said it had “high confidence that the Browser Extension v2.68 incident is likely related to the industry-wide Sha1-Hulud incident in November.” A Dune-themed exfil domain registered on December 8, 2025 sat in the same naming pattern as the worm.
Microsoft’s December 9, 2025 guidance told customers to review Key Vault assets, isolate CI agents and cut extra pipeline roles. That is the same posture as the Microsoft warning to change passwords that went out when the Dune-named worm first surged: rotate first, then prove the new secret is the only one still in use.
The SHA1HULUD Runner and discussion.yaml
Persistence was built into the November payload. Unit 42 and Microsoft both describe a GitHub Actions workflow, discussion.yaml, and a self-hosted runner named SHA1HULUD (Microsoft also saw SHA1Hulud). The installer dropped the official Actions runner tarball under ~/.dev-env, configured it against a new repo, and left a workflow that ran on discussion events with a command-injection hole. Opening a GitHub discussion was enough to run code on the infected machine after the npm install had finished.
Mini Shai-Hulud, which Microsoft dated to May 11, 2026, added another implant path. Microsoft said the campaign compromised 170-plus npm packages and 2 PyPI packages across 404 malicious versions, the first time this family hit both registries in one operation. A failed optional dependency still ran bun against an obfuscated stealer, then wrote Claude Code SessionStart hooks into.claude/settings.json,.claude/setup.mjs and a full payload copy at.claude/router_runtime.js, and committed those files into victim repos over GraphQL.
In September 2026 the same family showed up through GitHub Actions that teams had never unpinned. Researchers tracking Mini Shai-Hulud said actions-cool/issues-helper and actions-cool/maintain-one-comment came back online with the May malicious tags still attached, so any workflow that called those actions by version tag ran the payload again. OWASP London chapter leader Sam Stepanyan wrote that one of the actions still sat in about 15,000 dependent repositories. The fix he and others kept repeating was the unglamorous one: pin third-party actions to a full commit SHA, then rotate every secret that workflow could see.
HOW ACCESS SURVIVED THE TAKEDOWN
- Self-hosted runner: A runner named SHA1HULUD plus discussion.yaml let later GitHub discussion events execute on the box.
- Editor extension: asyncapi-preview 1.0.1 stayed installed until a higher clean version forced IDEs to update.
- CI cache: –prefer-offline and private pull-through mirrors kept revoked tarballs in the build path.
- Action tags: May 2026 Mini payloads on actions-cool tags ran again when those actions were re-enabled in September 2026.
- Editor hooks: Mini Shai-Hulud wrote Claude Code and VS Code hook files that executed the next time a developer opened the repo.
Microsoft’s August 4, 2026 Threat Intelligence post listed keyv@6.0.0, file-entry-cache@11.1.6, cache-manager@7.2.10 and a string of servicetitan packages among confirmed Mini variants. A preinstall hook launched setup.mjs, pulled a Bun binary, and ran a credential stealer that republished whatever packages the stolen npm identity could still sign. Defender’s alert name for that dropper was Trojan:npm/MalBun.A.
What npm Changed After the Second Coming
GitHub, which runs the npm registry, spent 2026 putting human checkpoints in front of publish. Maintainers can now use trusted publishing instead of stored tokens, so a CI job proves its identity with short-lived OIDC rather than a classic token sitting in a secret store. Staged publishing, shipped in the npm CLI 11.15.0 line, parks a tarball until a person completes 2FA. Stage-only granular tokens followed in September 2026 so automation can queue a release without the right to make it public. npm also began scanning packages at publish time in July 2026 and, in npm 12, stopped running install scripts unless a user opts in.
Those controls raise the cost of the original worm path, a stolen long-lived publish token that pushes a new version the moment the script finds it. They do nothing for a cloud key that left the building in November 2025, and they do nothing for a workflow that still calls a third-party action by a floating tag. On October 2, 2026, researchers were still telling teams to pin those actions-cool tags to commit hashes and to treat every secret that job could read as burned.
The packages from 2025 are gone from the public registry. The keys, the runner names and the tag pointers are the part that had to be hunted by hand, and some of them were still being hunted a year later.
-
BUSINESS4 months agoMusk’s $914 Billion Lead Is a Public SpaceX Bet
-
NEWS2 months agoMicrosoft’s 96% Cyber Score Sits at 86.3% on the Board
-
SPORTS3 months agoFree Live Sports Streaming in 2026: What to Watch Without Cable
-
ENTERTAINMENT3 months agoEndgame Encore’s $86 Million Trial for Infinity Vision
-
ENTERTAINMENT2 years agoAndrew Garfield’s Spider-Man Films Are No Longer Free
-
NEWS4 months agoSingapore’s 3×3 and Surfing Debuts Miss the Medal Stand
-
ENTERTAINMENT1 month agoSterling Point Holds No. 2 on Prime Video After 32 Days
-
NEWS6 months agoWhite Sands Footprints Put People in Ice Age New Mexico
