The Incident
On 14 July 2026, an attacker published five trojanized versions across four npm packages in the @asyncapi organization: @asyncapi/generator@3.3.1, @asyncapi/generator-helpers@1.1.1, @asyncapi/generator-components@0.7.1, @asyncapi/specs@6.11.2-alpha.1, and @asyncapi/specs@6.11.2. The affected packages together see more than 2.25 million weekly downloads. The malicious versions were published between roughly 07:10 and 08:30 UTC and — because they were built and released by AsyncAPI’s own release workflow — the tarballs shipped to the registry with valid npm OIDC provenance attestations under the legitimate maintainer identity. All five versions have since been unpublished and clean successors restored. No CVE or GHSA had been assigned at the time of writing.
The payload is a second-stage loader that activates on require() or import — not at npm install — which means the common --ignore-scripts mitigation does not apply. Once imported, the loader retrieves a Miasma-lineage RAT from IPFS and initiates command-and-control over HTTP endpoints on 85.137.53.71:8080/8081/8091, with documented fallback channels over Nostr, Ethereum, libp2p, and BitTorrent DHT. Wiz’s analysis records the framework’s internal identifier as M-RED-TEAM v6.4 under the campaign tag miasma-train-p1, and independent trackers (Microsoft, GitGuardian, Palo Alto Unit 42) place the compromise in the ongoing Miasma / “Mini Shai-Hulud” family that traces back to the TeamPCP campaigns of earlier in 2026.
MITRE ATT&CK coverage: T1195.002 (Compromise Software Supply Chain: Compromise Software Dependencies and Development Tools), T1528 (Steal Application Access Token), T1204.002 (User Execution: Malicious File), T1071.001 (Application Layer Protocol: Web Protocols).
The Authority Path That Failed
The identity that carried authority at the moment of failure was asyncapi-bot, a non-human identity whose Personal Access Token was held by the CI environment as a workflow secret. Its stated purpose was narrow — rendering Netlify docs previews for pull requests. Its held scope was much broader: organization-wide repository write, including the ability to push directly to the release-triggering next branch. The manual-netlify-preview.yml workflow used a pull_request_target trigger while also checking out the untrusted PR head — the canonical “pwn request” pattern. When PR #2155 was processed — opened by throwaway account elzotebo999 amid a smokescreen of roughly 36 spam pull requests — attacker-controlled code executed inside a job that held the bot PAT and exfiltrated it to an external paste service. Approximately 100 minutes later, the attacker used that PAT to push commit 3eab3ec to the next branch. AsyncAPI’s own release workflow then built and published the trojanized tarballs to npm, producing valid OIDC provenance attestations for artifacts a maintainer had never authored.
The trust anchor that failed first was scope containment on a CI-resident non-human identity. Every downstream control — branch pushability, release-workflow authenticity, npm publish authority, OIDC provenance — behaved exactly as designed once the first boundary broke. Endor Labs’ post-incident analysis notes that the release branches (master, next) carried no push protection or required-review policy, so a valid asyncapi-bot PAT was sufficient authority to trigger the publishing pipeline. The workflow weakness itself was not novel: a proof-of-concept had been filed on 29 April 2026 and a remediation pull request opened on 17 May 2026 — the remediation was still unmerged when the attack landed on 14 July.
SecurityV0 Perspective
The failure was not provenance. It was authority. A credential intended to render a docs preview could write across the organization, reach a release branch, and trigger a trusted publishing workflow. Valid npm provenance then proved only that AsyncAPI’s workflow built the package — not that a maintainer intended the release.
Security teams should trace each CI identity from its justified task through every workflow, branch, and release path it can reach. The decisive question is not whether the token is legitimate. It is whether one attacker-controlled pull request can turn that token into publishing authority.
What To Do
- Right-size every CI-resident PAT to the workflow that holds it. Replace organization-wide PATs held as GitHub Actions secrets with fine-grained tokens scoped to the single repository — and, where possible, the single branch — each workflow actually needs. A bot credential whose only job is rendering a docs preview must not carry release-branch write.
- Ban
pull_request_targetplus untrusted checkout in the same job as any secret. Treat this combination as a policy violation, not a code-review question. Enforce with a repository ruleset or an org-wide GitHub Actions policy, and alert on any workflow that referencesgithub.event.pull_request.head.reforhead.shainside a job that also referencessecrets.*. - Protect release-triggering branches with rules that survive a valid PAT. Require signed reviews and branch-protection status checks on
main,master,next, and any other branch that triggers a package-publishing workflow. A validasyncapi-botPAT was sufficient to reachnexthere — the equivalent branch on your side must not be equally exposed. - Do not treat npm OIDC provenance as proof of maintainer intent. OIDC attestation confirms that a specific workflow in a specific repository produced a specific artifact; it does not confirm that the commit the workflow built was authored by a human maintainer. Include the head commit’s authorship, signature, and branch-arrival path in your provenance checks, and quarantine releases where any of those diverge from historical norms.
- Detect import-time payloads, not just install-time scripts.
--ignore-scriptsdoes not stop code that runs onrequire(). Baseline the observable behavior of top-N direct and transitive dependencies at first import in a sandbox — outbound network to previously-unseen endpoints, IPFS gateway reads, filesystem access to credential paths — and alert on a delta from that baseline, per package version.
Sources
- Wiz Threat Research — M-Red-Team: AsyncAPI Supply Chain Compromise via GitHub Actions
- Microsoft Security Blog — Unpacking the AsyncAPI npm Supply Chain Compromise
- Datadog Security Labs — Compromised AsyncAPI npm Packages: Inside a CI Supply-Chain Attack
- StepSecurity — Coordinated AsyncAPI Supply Chain Attack: Miasma RAT via Compromised CI/CD Pipelines
- Chainguard Unchained — AsyncAPI Supply Chain Compromise via GitHub Actions “pwn request”
- Endor Labs — How Unprotected Release Branches Let Attackers Compromise AsyncAPI
- The Hacker News — Compromised AsyncAPI npm Packages Deliver Multi-Stage Botnet Malware
- MITRE ATT&CK: T1195.002, T1528, T1204.002, T1071.001