npm launched Package Provenance in late 2022. For two years, adoption averaged 20-50 packages per week. Followed by Trusted Publishing in 2024. Blog posts were written. CISA advisories were issued. The line barely moved. Eventually Trusted Publishing with OIDC was made Generally Available in July 2025
Then Shai-Hulud hit. Weekly adoption jumped to 430 packages. In 18 months, cumulative adoption grew 3.4x. We're still only at 25% of total download volume covered, just 11,001 of the top 51,370 packages have adopted it. But the attacks moved the needle more than anything the security industry did.
Here's the data.


What Trusted Publishing is
Trusted Publishing replaces long-lived npm API tokens with short-lived, per-run credentials issued via OpenID Connect. Instead of storing NPM_TOKEN in your GitHub repo secrets indefinitely, your CI pipeline gets a token that expires in minutes. Nothing to steal. Nothing to exfiltrate.
The attack wave that changed things
August 26, 2025: S1ngularity. Attackers exploited a GitHub Actions misconfiguration in the Nx monorepo to execute code from a malicious fork in the upstream repo's trusted context, stealing the npm publishing token. Malicious versions of several Nx packages were live for four hours, scanning developer machines for credentials, SSH keys, crypto wallets — and notably, actively searching for installed AI CLI tools to run them with --dangerously-skip-permissions and extract filesystem contents. That week: adoption ticked up noticeably for the first time.
September 8, 2025: Debug/Chalk. A maintainer was phished via a fake npm support email (sent from npmjs.help) that harvested their credentials and live TOTP code. 18 packages with over 2 billion combined weekly downloads were backdoored with a crypto-theft payload that silently intercepted browser wallet interactions and redirected funds. Malicious versions were live for two hours. That week: 103 new packages adopted Trusted Publishing.
September 15, 2025: Shai-Hulud wave 1. A self-replicating worm hit the npm ecosystem. When a compromised package found additional npm tokens in its environment, it automatically published malicious versions of anything else it could reach. Result: 700+ packages compromised, 27,000 malicious GitHub repositories, 14,000 secrets exposed across 487 organizations. CISA issued an alert September 23. That week: 109 new packages.
November 23, 2025: Shai-Hulud 2.0. A Pwn Request against the asyncapi/cli repository exfiltrated the CI token in under three minutes, then used it to deploy the worm via a malicious OpenVSX extension. The campaign spread to 25,000+ malicious repositories. Microsoft published guidance on December 9. That week: 372 new packages. The previous two-year weekly average was around 40.
November 24, 2025: SHA1-Hulud. A parallel wave hit Zapier, ENS Domains, and others. Long-lived credentials were found sitting in compromised repositories. npm's security team explicitly recommended Trusted Publishing as the fix. That week: 120 new packages.
March 20–21, 2026: CanisterWorm. TeamPCP deployed an npm worm via stolen tokens. 28+ packages infected in under 60 seconds; the payload harvested credentials and self-propagated. That week: 112 new packages.
March 31, 2026: Axios. Sapphire Sleet (North Korea) compromised a maintainer account and published two backdoored versions 39 minutes apart, each injecting a fake dependency that silently downloaded a cross-platform remote access trojan. The malicious packages were live for three hours. Axios has 100M+ weekly downloads. That week: 138 new packages.
April 8–22, 2026: CanisterSprawl. A second TeamPCP npm worm using a new ICP canister. When PyPI tokens were discovered in infected environments, it jumped ecosystems via .pth injection. That week: 163 new packages.
April 29–30, 2026: Mini Shai-Hulud I. TeamPCP pivoted from token theft to stolen CI credentials. A cross-ecosystem attack hit npm, PyPI, and Packagist in 24 hours via compromised CircleCI tokens. That week: 121 new packages.
May 7–11, 2026: Mini Shai-Hulud II / TanStack. Here's the escalation that changes everything: they didn't steal a token. TeamPCP used a Pwn Request to poison the GitHub Actions cache, then waited for the legitimate release workflow to run. When it did — with id-token: write permissions — attacker-controlled code from the poisoned cache extracted the OIDC token from runner memory and exchanged it through npm's own token endpoint. The published packages carried valid SLSA Build Level 3 provenance attestations. Trusted Publishing wasn't bypassed. It was used as the attack vector. 170+ packages across npm and PyPI in 5 hours.
May 18–19, 2026: Mini Shai-Hulud III / Nx & AntV. The Nx Console VS Code extension was compromised using credentials stolen during the TanStack attack — five days of dwell time before use. 639 @antv npm versions were poisoned via a stolen maintainer account, each installing a persistent kitty-monitor backdoor. That week: 144 new packages. The week after: 430. An all-time high.
June 1–7, 2026: Miasma / Hades. The attack class shifted again. Wave 1 published 90 malicious npm versions targeting Red Hat Cloud Services packages — not by stealing OIDC tokens, but by abusing the OIDC publishing endpoint directly. Wave 2 added a binding.gyp technique to bypass install-script detection. By wave 4 (Hades), the campaign had crossed to PyPI via .pth startup execution, poisoning 37 wheels across 19 packages. Red Hat issued RHSB-2026-006. That week: 209 new packages.
The pattern, and how it escalated
The early attacks followed a familiar script: phish a maintainer, steal a long-lived token, publish malware, spread to everything else the token can reach. Debug/Chalk was a phishing attack. Axios was a compromised maintainer account.
But the more sophisticated attacks went after the CI pipeline itself. S1ngularity and Shai-Hulud 2.0 both used Pwn Requests, malicious pull requests that exploited vulnerable pull_request_target GitHub Actions workflows to execute attacker code inside the upstream repo's trusted context. They didn't need to steal a stored token. They just needed the CI runner to have one.
Mini Shai-Hulud II was the logical endpoint of one progression. Once you control the runner, you can extract whatever ambient credentials are present, including short-lived OIDC tokens. The packages it published looked legitimate by every automated check: valid provenance, real maintainer identity, correct signing. The attack had evolved from exploiting stored secrets to exploiting the build process itself.
Miasma escalated further still. It didn't need to extract a token at all: it abused the OIDC publishing endpoint directly. Each wave introduced a new detection-bypass technique. The postmortems kept naming the same failures. The attacks kept finding new ways around the recommended fixes.
The attack surface is now meaningfully smaller than 18 months ago. Not because the security industry convinced people. Because packages got backdoored, and then maintainers changed their setup.
That's not a win for security education. It's a data point about how security decisions actually get made in practice.
Who was this?
During the Shai-Hulud 2.0 campaign, the attacker renamed their GitHub account to UnknownWonderer1 — almost certainly a reference to the Zensunni Wanderers from Dune: the persecuted nomads who became the Fremen, the only culture that learned to live in harmony with Shai-Hulud. The name is not the work of someone who stumbled into the ecosystem. It is the name of someone who had been thinking about it.
The malware design reinforces that read. S1ngularity didn't quietly exfiltrate credentials — it injected a shutdown command into the shell profile, something that would visibly kill your machine the next time you opened a terminal. That is not the behaviour of someone trying to stay hidden. Every campaign stopped well short of what it could have done. A worm that self-propagates to 700+ packages but restrains its payload is making a choice.
They also understood the incentive structure better than the ecosystem did. Maintainers are rarely paid to secure packages. The blast radius of a breach lands on downstream users, not on the person who left the token in CI. The platforms with the power to mandate secure publishing feel the least pain when it goes wrong. It is a classic collective-action failure — and 40,000 unprotected packages after three years of advisories is exactly what that structure produces. This attacker understood why nothing was moving. And they decided to apply a different kind of pressure.
Warning shots
I wrote about this at the time: the naming, the restraint in the malware design, and the way the attacks consistently stopped short of full exploitation. My read is that Shai-Hulud was not primarily a criminal operation. It was a message — from someone who understood the ecosystem well enough to know exactly which pressure points would make it move.
The Fremen pray that the Maker's passage will cleanse the world. The attacker appears to have reached a similar conclusion: only visible pain would force the ecosystem to confront what made the worm possible. To the Fremen, Shai-Hulud is not simply a destructive animal. It is the Maker. Its passage tears through the desert, but it also cleanses and enforces the laws by which everything in that ecosystem must live.
They did not merely release Shai-Hulud.
They chose to play the Wanderer who understood why it had to come.
Why we still haven't fixed it
The warning was issued. The ecosystem didn't move fast enough. The open-sourced Shai-Hulud playbook then got picked up by actors with no interest in sending a message — TeamPCP, Sapphire Sleet, and others who went straight for credential theft, crypto wallets, and remote access. Frameworks like Mastra became victims. The worm that started as a demonstration became a template.
The frustrating part is that the holdout isn't a technical difficulty. Trusted Publishing is free and takes ten minutes. The holdout is that the cost of not doing it hasn't landed on the right person yet. Maintainers bear the reputational risk if their package gets compromised, but the actual damage lands downstream on teams who didn't write a single line of the affected package. That misalignment is structural. Attacks spike adoption temporarily, then urgency fades, and the next cohort of packages defaults back to long-lived tokens.
Look at the chart. The spikes are real. So is the decay between them.
And Mini Shai-Hulud added a new wrinkle: even packages that adopted Trusted Publishing can be compromised if the underlying CI pipeline isn't hardened. Extracting an OIDC token from runner memory is harder than stealing a stored secret. But it's not impossible, and the attack now has a public proof of concept. Trusted Publishing removes one attack vector. It doesn't remove all of them.
The accountability gap, and what to do about it
Axios had over 100 million weekly downloads and hadn't adopted Trusted Publishing before North Korea compromised it. Someone could have filed a PR a year earlier. Nobody did.
That's the accountability gap. The security community publishes advisories, writes postmortems, and waits for the next attack to move the needle. There's a more constructive version of the same pressure: proactively going after the 40,000 packages that haven't switched, the way Let's Encrypt went after HTTP. File PRs. Open issues. Name the high-download packages that are still running long-lived tokens. Make the social cost of not adopting TP higher than the ten minutes it takes to fix it.
This is the kind of activism the ecosystem actually needs. Not another CISA advisory. Not another blog post that gets read and forgotten. Specific, targeted, uncomfortable pressure on specific maintainers of specific packages — the ones with 10M+ weekly downloads that are still one phished credential away from becoming the next incident.
The security industry has known what the fix is for three years. The question is whether we're willing to make it socially unacceptable to ignore it.
40,000 of the top 51k packages still haven't switched
11,001 packages have adopted Trusted Publishing. Those 11k happen to represent about 25% of total download volume, because some of the biggest packages made the switch after each wave of attacks. But that leaves 40,369 packages (75% of download volume) still publishing with long-lived tokens.
If you maintain an npm package, go do it now. The documentation is here. Four lines of YAML and a checkbox. Then make sure your GitHub Actions workflows don't have pull_request_target without explicit trust boundaries, that's the vector Mini Shai-Hulud used to extract the OIDC token even after TP was in place.
If you depend on packages that haven't switched, file an issue. Open a PR. The maintainer may not know Trusted Publishing exists, or may just need someone to make the inaction feel more uncomfortable than the ten-minute fix.
The sandworm in Dune is called Shai-Hulud, which means "the great old man of the desert." The Fremen don't celebrate when it destroys something. They understand that its passage shapes the ecosystem in ways nothing else can.
That's the uncomfortable truth at the center of this post. The attacks worked. Pain moved the needle in ways three years of advisories couldn't.
We've learned the lesson. The ecosystem moves under pressure, and it doesn't have to come from a worm. The Wanderer understood why the Maker had to come. We're working on making the next one unnecessary.
More on that soon.

