Asyncapi NPM Supply Chain Attack
Published on gastropod.io on 07-16-2026
A Valid Signature Isn't the Same as a Safe Package
Every few weeks this year there's been a new npm compromise to write about, and most of them follow the same script: a stolen token, a postinstall hook, a scramble to pull versions before too many npm install runs finish. The one that broke on July 14 doesn't follow that script, and that's the part actually worth paying attention to.
Microsoft's threat intelligence team published a detailed breakdown of a compromise hitting the @asyncapi npm organization, the packages behind the AsyncAPI spec and its code generator tooling. Five versions across four packages went out within about ninety minutes: @asyncapi/generator, @asyncapi/generator-components, @asyncapi/generator-helpers, and both a prerelease and stable build of @asyncapi/specs. Because @asyncapi/specs sits transitively under a lot of other AsyncAPI tooling, the actual blast radius reached further than four package names would suggest.
The mechanics are the part that should make anyone running a registry uncomfortable. The attacker didn't touch npm credentials at all. They opened a pull request against asyncapi/generator that exploited a pull_request_target workflow, the classic "pwn request" pattern, where a workflow checks out untrusted PR code but runs with the base repository's privileges and secrets. That got them a bot token, and from there they pushed commits that the project's own legitimate GitHub Actions release pipeline picked up and published, using npm's trusted-publishing OIDC flow. The resulting packages carried entirely valid provenance attestations. They correctly named the real repository, the real commit, the real workflow. Every one of those facts was true. None of it meant the code was safe, because the commit itself was unauthorized.
The payload was also built to dodge the mitigation everyone's been leaning on this year. It declared no preinstall or postinstall hooks at all, so npm install --ignore-scripts (the advice repeated in nearly every writeup since the Shai-Hulud incidents) did nothing. Instead it fired at require() or import time, the moment any application actually loaded the module, spawning a hidden child process that pulled a second-stage payload off IPFS. That payload turned out to be a build of the Miasma runtime, the same malware family behind the @redhat-cloud-services compromise back in June, with credential harvesting and propagation modules present in the code but switched off in this particular run.
A few other pieces worth reading if you want the full shape of it: Red Hat's own advisory on the earlier Miasma incident traces the malware family back to a compromised VS Code extension, and GitHub's changelog on trusted-publishing config and script security gives useful context on why "the attestation checks out" has become such a common but incomplete signal this year.
- Microsoft: Unpacking the AsyncAPI npm supply chain compromise and import-time payload delivery
- Red Hat: RHSB-2026-006, supply chain compromise of @redhat-cloud-services npm packages
- GitHub: npm bulk trusted publishing config and script security
What actually would have shortened this incident isn't a smarter scanner sitting on the install hook. The whole point of this campaign was that there was no install hook to catch. It's the two things a lot of registries still treat as separate products: knowing instantly who resolved that exact package digest, and knowing instantly what else in your org depends on it, transitively, the second an advisory or a bad version shows up. That's the gap between "our provenance check passed" and "we know it's safe," and it's the reason we built the where-seen and blast-radius graph into the artifact record itself in Gastropod, rather than as a bolt-on report you generate after the fact. When a package like this gets flagged, the question that matters isn't just "was this signed correctly." It's "which of our services already pulled it, and from where." If you want to see how that maps against the identity and provenance layer specifically, the product walkthrough has a rundown of how the intake pipeline handles this.
Valid provenance is a necessary check. This one's a good reminder it was never meant to be the only one.