The four npm packages that carried a malware loader into JavaScript build pipelines last week were not typosquats, and they were not published with a stolen maintainer token. They shipped from the @asyncapi project's own release automation, and they arrived with valid provenance attestations that said exactly that. The cryptographic signature was real. The code sitting under it was a remote access trojan.
That inversion is the story, and most of the coverage walked past it. For two years the supply-chain conversation has pushed maintainers toward npm's trusted-publisher model and Supply-chain Levels for Software Artifacts (SLSA) provenance: cryptographic proof that a package was built by the pipeline it claims to come from. In this incident an attacker got that proof to vouch for malware. According to researchers at OX Security, Socket, StepSecurity and others who pulled the packages apart, the intruder gained push access to the repositories and let each project's real GitHub Actions release workflow do the publishing through npm's OIDC trusted-publisher integration. The provenance was honest about where the build ran. It said nothing about who pushed the commit or what the commit contained.
What shipped, and for how long
Four packages in the @asyncapi namespace were replaced with malicious versions on July 14, 2026: @asyncapi/specs (2.1 million weekly downloads), @asyncapi/generator, @asyncapi/generator-helpers, and @asyncapi/generator-components. Five malicious versions in total, because specs shipped both a stable and an alpha build. Combined, the four packages pull more than 2.25 million downloads a week, so the blast radius was large even though the window was short. Researchers put the exposure at roughly four hours on July 14, opening around 07:10 and closing near 11:18 UTC, after which every malicious version was pulled from the registry.
| Package | Malicious version | Weekly downloads |
|---|---|---|
| @asyncapi/specs | 6.11.2, 6.11.2-alpha.1 | 2.1M |
| @asyncapi/generator | 3.3.1 | 101k |
| @asyncapi/generator-helpers | 1.1.1 | 43k |
| @asyncapi/generator-components | 0.7.1 | 34k |
Why the provenance checkmark did not help
Provenance answers one question well: was this artifact built by the pipeline it says it was? It does not answer the two that matter more once an attacker is inside the repository. Who authorized the change, and is the code safe to run? The attacker reportedly committed under a throwaway git identity, then let the project's real release workflow sign and publish the poisoned build for them. Every automated integrity control did its job. They just attested to a build that was already poisoned upstream.
That has a concrete consequence for anyone who has been tightening install policy. A rule that says "only install packages with valid provenance" would have waved these five versions straight through, because they had it. Provenance raises the cost of one attack class, the offline forge and the leaked token, and does nothing about the class on display here, where the pipeline itself is the entry point. We made the same point when the toolchain, not the code, was the attack in an earlier compromise we covered, and it holds again: the trust boundary moved to the build system, and the build system is now the target.
The install-script block is the wrong tripwire
npm 12 turned off lifecycle install scripts by default, and that change genuinely killed a large share of install-time malware. We flagged the blind spot at the time: it only covers packages that run code during npm install. This campaign never touches install scripts. The malicious statement sits in each package's main JavaScript module, so it fires when a build or continuous-integration job calls require() on the package, not when the package is installed. It is the same execution model as the editor-triggered npm stealer we wrote up, where merely opening the project ran the code.
So if your supply-chain posture leans on "we block install scripts," this walks past it, and so does a triage rule that deprioritizes packages with no install hook. The trigger is ordinary import during a build. That is not an edge case; it is how every one of these packages is meant to be used.
Where a defender should actually look
The compromised asset here is mostly not developer laptops. It is build agents and CI runners, because that is where an @asyncapi code generator actually gets imported and run. Treat any runner or workstation that pulled an affected version inside the July 14 window as potentially compromised, rotate the credentials and tokens that were reachable from those jobs, and remember that ephemeral runners may already be gone: pull their logs and any build artifacts or caches produced in that window before they age out.
For detection, watch build-system egress rather than lockfiles. The loader pulled an encrypted second stage from the IPFS peer-to-peer network (ipfs.io) and, per the analyses, the unpacked framework carried six command-and-control channels including IPFS, BitTorrent's distributed hash table, Nostr relays, and Ethereum smart contracts. A build agent reaching out to an IPFS gateway or a BitTorrent bootstrap node is not normal traffic, and it is a far more reliable signal than trying to fingerprint the payload. One useful caveat from BleepingComputer's analysis: several of the framework's stealer functions did not actually work in the deployed build, which suggests a rushed or staged release. Do not let a half-functional sample lull the triage. The delivery mechanism, provenance-signed and import-triggered, is the durable threat here, not this particular payload.
The pattern is escalation up the toolchain
Line up the recent npm incidents and the direction is clear. Packages that passed inspection and turned hostile a day later. Malware that runs at open or import instead of install. And now packages published straight through the maintainer's own pipeline with genuine provenance. Attackers have moved from forging trust to inheriting it. Provenance and script-blocking are both worth having, and neither is close to sufficient on its own. The one control that would have caught this is the least automated one: treating write access to a release pipeline, and the pipeline's own runners, as production infrastructure that gets monitored like production, not as plumbing nobody watches. Attribution, for what it is worth, remains unsettled: researchers tie the payload to a framework tracked as Miasma but note it could be the original operators or a group reusing the name.