Home/ Blog/ Security news/ Article
Blog · Security news

AsyncAPI's npm packages shipped malware with valid provenance. The supply-chain checkmark waved it through.

Four @asyncapi npm packages shipped a malware loader carrying valid OIDC provenance attestations. Why signed provenance and npm's install-script block both

Conveyor of sealed crates, one transparent crate exposing tangled machinery inside

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.

2.25M+
Weekly downloads exposed
across the four packages
4h 7m
Exposure window
on July 14, 2026
5
Malicious versions
published with valid provenance

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.

PackageMalicious versionWeekly downloads
@asyncapi/specs6.11.2, 6.11.2-alpha.12.1M
@asyncapi/generator3.3.1101k
@asyncapi/generator-helpers1.1.143k
@asyncapi/generator-components0.7.134k
Compromised @asyncapi versions and their weekly npm download volume. Source: OX Security, Socket, StepSecurity, BleepingComputer.

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.

Topics

Frequently asked questions

Which npm packages were compromised in the AsyncAPI attack?

Four packages in the @asyncapi namespace shipped malicious versions on July 14, 2026: @asyncapi/specs (6.11.2 and 6.11.2-alpha.1), @asyncapi/generator (3.3.1), @asyncapi/generator-helpers (1.1.1), and @asyncapi/generator-components (0.7.1). All malicious versions were unpublished from npm within hours.

Did the malicious packages have valid provenance?

Yes. Researchers reported the attacker used the AsyncAPI project's own GitHub Actions release workflow and npm's OIDC trusted-publisher integration, so the packages carried valid SLSA provenance attestations. Provenance proves which pipeline built a package, not whether its code is safe.

Does npm's install-script block stop this malware?

No. The payload sat in each package's main JavaScript module, not a lifecycle install script, so it runs when the code is imported during a build or CI job. The default block on install scripts added in npm 12 does not cover import-time execution.

When does the AsyncAPI malware execute?

It runs at import time, when a build or CI job calls require() on the affected package, not during npm install. A staged loader then pulls an encrypted second stage from the IPFS peer-to-peer network and unpacks a modular remote access framework.

How should teams that installed these versions respond?

Treat any developer machine or CI runner that imported an affected version between roughly 07:10 and 11:18 UTC on July 14, 2026 as compromised. Rotate credentials and tokens reachable from those build jobs, pull CI logs, and check build agents for outbound connections to IPFS gateways or BitTorrent nodes.

Who was behind the AsyncAPI npm compromise?

Attribution remains uncertain at the time of writing. Researchers linked the payload to a framework tracked as Miasma but noted it could be the original operators or a separate group reusing the name. AsyncAPI is the compromised project, not the attacker.

Ready to meet the Guardians?

Deploys fast - agentless for monitoring and cloud, a lightweight agent for deep endpoint security. Just Suriq, standing watch.