On 24 November 2025, a second wave of the Shai-Hulud npm worm, labelled by its authors "Sha1-Hulud: The Second Coming", began publishing trojanised versions of packages from Zapier, ENS Domains, PostHog, Postman and AsyncAPI. The malicious code ran in the preinstall step, used the Bun runtime to launch a large obfuscated payload, and hunted for npm tokens, GitHub tokens and cloud credentials on every developer laptop and CI runner that installed it. Stolen secrets were dumped into public GitHub repositories, and Wiz counted more than 25,000 of them within days. Any stolen npm token was then used to republish the victim's own packages, so each compromised identity became a new source of infection. The wave followed a first Shai-Hulud outbreak in September 2025 that compromised more than 500 packages and prompted a CISA alert. Both waves show how publishing tokens and CI secrets, not human passwords, drive modern supply chain attacks.
Key takeaways
- The first wave surfaced on 15 September 2025 with @ctrl/tinycolor, spread to more than 500 packages and led CISA to issue an alert on 23 September 2025.
- The second wave started in the early hours of 24 November 2025 (UTC). Researchers counted between roughly 490 and 800 affected packages, depending on method, and more than 25,000 GitHub repositories holding stolen secrets.
- At PostHog, the entry point was a bot's GitHub personal access token stolen through a misconfigured
pull_request_targetworkflow, which then exposed the npm publishing token held in GitHub secrets. - Wiz found that 77% of infections were on CI/CD runners rather than developer machines, putting pipeline secrets at the centre of the damage.
- Lesson: long-lived publishing tokens and broadly scoped CI secrets turn one leak into ecosystem-wide spread. npm revoked all classic tokens on 9 December 2025.
At a glance
| Organisation(s) | npm ecosystem; publishers including Zapier, ENS Domains, PostHog, Postman and AsyncAPI in the second wave, and @ctrl/tinycolor and hundreds of other packages in the first; developers and CI systems that installed affected versions |
|---|---|
| When | First wave from 15 September 2025; second wave ("The Second Coming") from 24 November 2025 |
| Attacker | Unattributed in the sources used here |
| Entry point | Stolen maintainer and CI credentials used to publish trojanised packages; at PostHog, a bot GitHub token stolen via a vulnerable GitHub Actions workflow |
| Identities abused | npm publishing tokens, GitHub personal access tokens, GitHub Actions secrets, AWS, GCP and Azure credentials, cloud secret stores, self-hosted GitHub runner registrations |
| Impact | Second wave: about 800 packages and 25,000+ exfiltration repositories according to Wiz; 796 packages and 1,092 versions according to Datadog; 492 packages with 132 million monthly downloads according to Aikido |
| Category | NHI (publishing tokens, CI and cloud secrets), software supply chain |
What happened
The first wave, September 2025. On 15 September 2025, StepSecurity reported that versions 4.1.1 and 4.1.2 of @ctrl/tinycolor, a library with more than 2 million weekly downloads, had been trojanised. The malicious code was a minified file of about 3.6 MB called bundle.js. It "repurposes open-source tools like TruffleHog to scan the filesystem for high-entropy secrets", according to StepSecurity, and looked for AWS keys, GitHub tokens, GCP credentials and Azure access tokens. It created public repositories named "Shai-Hulud" to hold what it stole, and pushed a workflow file, .github/workflows/shai-hulud-workflow.yml, designed to "exfiltrate repository secrets using the expression ${{ toJSON(secrets) }}". Its spreading routine looked up the other packages the victim maintained and "force-publishes patches to these packages".
StepSecurity and CISA both put the first wave at more than 500 packages. CISA's alert of 23 September described "a self-replicating worm, publicly known as 'Shai-Hulud'" that spread "by authenticating to the npm registry as the compromised developer". CISA advised organisations to pin dependencies to releases from before 16 September 2025 and to "Immediately rotate all developer credentials".
The second wave, November 2025. Wiz saw the first GitHub repositories containing leaked secrets at 01:22 UTC on 24 November 2025, with the earliest malicious package versions uploaded to npm at around 03:00 UTC. Aikido identified its first malicious packages at 03:16 UTC, starting with go-template and 36 AsyncAPI packages. Datadog says the last affected package was published at about 18:00 UTC the same day, after npm put preventative measures in place.
This time the code ran earlier. Infected packages added a preinstall script. As Aikido puts it, the malware installs Bun "with the file setup_bun.js and then uses that to execute bun_environment.js", the real payload. Wiz says the payload checks environment variables such as GITHUB_ACTIONS to tell CI runners from developer machines, and bundles official cloud SDKs so it can read AWS Secrets Manager, Google Secret Manager and Azure Key Vault as well as local credential files and cloud metadata services. Secrets were published to public GitHub repositories with the description "Sha1-Hulud: The Second Coming."
The worm spread by reusing stolen npm tokens. Datadog says it would "backdoor the first 100 entries" of packages owned by the compromised user. When a victim had no usable credentials, it would "proactively search GitHub for credentials exfiltrated off other victims" and reuse those. For persistence, Wiz and Datadog describe a workflow, .github/workflows/discussion.yaml, and a self-hosted GitHub runner named SHA1HULUD registered on infected machines, allowing the attacker to run commands later through GitHub discussions.
The second wave also added sabotage. According to Aikido, "If it can't authenticate with GitHub or NPM, it will wipe all files in the users Home directory." Aikido linked the timing to npm's announcement that it would revoke classic tokens on 9 December.
How PostHog was hit. PostHog's post-mortem gives the clearest public account of an entry point. An engineer had changed a reviewer-assignment workflow to run on pull_request_target, but the workflow then checked out the pull request's own code, so "the code being run was controlled by the PR author." On 18 November an attacker opened a pull request that stole a bot's GitHub personal access token. On 23 November the attacker tested the token and then modified a workflow to exfiltrate all GitHub secrets, including the npm token. At 04:11 UTC on 24 November, malicious PostHog packages were published to npm.
Timeline
| Date | Event |
|---|---|
| 15 September 2025 | StepSecurity reports trojanised @ctrl/tinycolor 4.1.1 and 4.1.2 and a self-replicating worm across npm. |
| 23 September 2025 | CISA issues an alert on the Shai-Hulud worm, which it says affected more than 500 packages, and urges credential rotation. |
| 18 to 23 November 2025 | Attacker steals a PostHog bot token through a malicious pull request, then exfiltrates PostHog's GitHub secrets, including its npm token. |
| 24 November 2025, 01:22 to 03:16 UTC | First exfiltration repositories appear and the first malicious package versions are uploaded, according to Wiz and Aikido. |
| 24 November 2025, 04:11 UTC | Malicious PostHog packages published to npm. |
| 24 November 2025, around 18:00 UTC | Last affected package published, according to Datadog. |
| 26 November 2025 | Wiz reports GitHub's mitigation has cut public exfiltration repositories from thousands to about 300. |
| 9 December 2025 | npm permanently revokes all classic tokens and moves npm login to two-hour sessions. |
How it happened: the identity attack path
- A CI identity stolen first. At PostHog, a workflow that ran untrusted pull request code in a privileged context leaked a bot's GitHub personal access token, which gave access to repository secrets.
- Publishing token extracted. The npm token stored as a GitHub secret was exfiltrated through a modified workflow. With it, the attacker could publish as the organisation without touching any human account.
- Code runs before install finishes. The
preinstallhook executed on every developer machine and CI runner that pulled an affected version, with no user interaction. - Secrets harvested at scale. The payload collected GitHub tokens, npm tokens and cloud credentials from files, environment variables, metadata services and cloud secret stores, and ran TruffleHog to find more.
- Stolen identities reused to spread. Each valid npm token was used to republish up to 100 of the victim's packages. Tokens already dumped on GitHub were harvested again by later infections.
- Persistence through a machine identity. Infected hosts were registered as a self-hosted GitHub runner named SHA1HULUD, giving the attacker a standing route back in.
- Destruction as a fallback. Where it could not authenticate to GitHub or npm, the malware tried to wipe the user's home directory.
Impact
- Packages: figures differ by source and by date. Wiz identified about 800 affected packages; Datadog counted 796 packages and 1,092 versions with more than 20 million weekly downloads; Aikido's updated count is 492 packages with 132 million monthly downloads. The first wave affected more than 500 packages according to StepSecurity and CISA.
- Exfiltration repositories: Wiz reported more than 25,000 repositories across about 500 GitHub users, growing by around 1,000 every 30 minutes at its peak. Aikido counted 26,300 repositories exposing stolen credentials.
- Credentials: Wiz's early count included 775 compromised GitHub tokens, 373 AWS credentials, 300 GCP credentials and 115 Azure credentials. In its follow-up of 1 December, Wiz said more than 60% of leaked npm tokens were still valid.
- Where it ran: Wiz found 77% of infections on CI/CD runners and 23% on developer machines, with GitHub Actions the most common platform.
- Victims' response: Zapier, PostHog and Postman published incident disclosures, according to Wiz.
What this means for NHI governance
Shai-Hulud is a non-human identity problem at every stage. The PostHog entry point was a bot token, not a person. The worm published with an npm token stored as a CI secret, and hunted for machine credentials: GitHub and npm tokens, cloud keys and secret store contents. Its persistence was a self-hosted runner, another machine identity. Human accounts barely appear in the attack path.
The worm works because these identities are long-lived and broadly scoped. A single npm token could publish up to 100 packages. A CI job that installs dependencies often has access to every secret in the repository. Wiz's finding that more than three quarters of infections were on CI runners shows where those secrets sit. Wiz's report that most leaked npm tokens were still valid a week later shows how slowly organisations rotate them, even when they are public.
The platform response points in the same direction. npm revoked every classic token on 9 December 2025, limited new write tokens to a maximum of 90 days and replaced long-lived login tokens with two-hour sessions. PostHog moved to trusted publishing, which removes the stored publishing token altogether. Later worms, such as ChainDrop in 2026, show that attackers adapt by targeting the maintainer and the workflow instead, so removing static tokens is necessary but not sufficient.
Recommendations
- Remove stored publishing tokens. Publish through trusted publishing where the registry supports it, and where a token is unavoidable make it granular, short-lived and scoped to one package.
- Harden workflows that touch secrets. Never run pull request code under
pull_request_targetor other privileged triggers, require review for workflow changes, and give bot tokens the smallest scope possible. The CI/CD Pipeline Identity Security Guide covers this in detail. - Disable install scripts by default. Use
--ignore-scriptsor a package manager that blocks lifecycle scripts unless allowed, particularly on CI runners. - Keep secrets out of dependency installs. Do not expose cloud or publishing credentials to jobs that install third-party packages; fetch them only in the steps that need them, as described in the Secrets Management Guide.
- Rotate fast and completely. After exposure, rotate npm, GitHub and cloud credentials the host could reach, and check GitHub for unexpected repositories, workflows and self-hosted runners. Challenges of Rotating NHIs explains why this is hard at scale.
- Inventory who can publish. Keep a record of which people, bots and tokens can publish each package, and remove any that are not needed, following the NHI Lifecycle Management Guide.
Frequently asked questions
What is the Shai-Hulud npm worm?
Shai-Hulud is a self-replicating npm malware campaign that steals developer and cloud credentials and uses stolen npm tokens to republish the victim's own packages. It first appeared in September 2025 and returned on 24 November 2025 as "Sha1-Hulud: The Second Coming".
How did Shai-Hulud 2.0 get into npm packages?
Through stolen publishing credentials. In PostHog's case, an attacker used a vulnerable GitHub Actions workflow to steal a bot token, then extracted the npm token from GitHub secrets and published malicious versions. After that, the worm reused every npm token it stole to infect more packages.
What should I do if I installed an affected package?
Treat the machine or CI runner as compromised. Remove the malicious versions, check GitHub for repositories described as "Sha1-Hulud: The Second Coming", unfamiliar workflows and a runner named SHA1HULUD, and rotate npm, GitHub and cloud credentials the host could reach.
Related NHI Mgmt Group resources
ChainDrop npm worm 2026 · Miasma and Hades worms · Malicious Nx package attack · GlassWorm campaign 2025 · CI/CD pipeline exploitation · NHI breaches
How NHI Mgmt Group can help
Shai-Hulud spread on npm tokens, bot tokens and CI secrets that few organisations had inventoried or scoped. Our NHI Foundation Level Training Course gives teams the practical grounding to find, govern and rotate these non-human identities before a worm does it for them.
References
- Wiz: Sha1-Hulud 2.0 Supply Chain Attack, 25K+ Repos Exposing Secrets (24 November 2025)
- Wiz: Shai-Hulud 2.0 Aftermath, Trends, Victimology and Impact (1 December 2025)
- Aikido: Shai Hulud 2.0 Strikes Again, Malware Supply-Chain Attack Hits Zapier and ENS Domains (24 November 2025, updated 17 March 2026)
- Datadog Security Labs: The Shai-Hulud 2.0 npm worm, analysis, and what you need to know (25 November 2025, updated 4 December 2025)
- PostHog: Post-mortem of Shai-Hulud attack on November 24th, 2025 (26 November 2025)
- StepSecurity: Shai-Hulud, Self-Replicating Worm Compromises 500+ NPM Packages (15 September 2025)
- CISA: Widespread Supply Chain Compromise Impacting npm Ecosystem (23 September 2025)
- GitHub Changelog: npm classic tokens revoked, session-based auth and CLI token management now available (9 December 2025)