At 5:08 a.m. UTC on July 14, an account nobody at AsyncAPI recognized began filing pull requests against the project's flagship code generator on GitHub. Over the next hour, it filed 36 more, each proposing the same small addition: a page thanking the project's financial donors.
One of the 37 was not a donation page.
Buried inside pull request #2155 was a markdown file padded with roughly a thousand blank characters, hiding a short piece of obfuscated JavaScript past the point where most code editors stop showing text on screen. When AsyncAPI's continuous integration system ran its usual checks against the incoming pull request, that hidden script quietly copied a privileged access token and sent it to a public pastebin. Eight minutes later, the workflow finished. The attacker had what they needed.
By 7:10 a.m. UTC, three new versions of AsyncAPI's npm packages were live on the public registry, each one signed with the project's own cryptographic seal of authenticity. Within the next ninety minutes, two more followed. All five carried a hidden payload built to steal browser passwords, SSH keys, and cryptocurrency wallets, and together the affected packages saw an estimated 2.9 million downloads a week.
Thirty-Six Decoys Covered One Real Attack
AsyncAPI is not a household name outside backend engineering, but its tooling sits deep in the plumbing of event-driven software. The @asyncapi/generator package and its companions scaffold client and server code, documentation, and validation logic from AsyncAPI specification files, the JSON-based format many companies use to describe asynchronous APIs the way OpenAPI describes REST ones. @asyncapi/specs, published from a separate AsyncAPI repository, supplies the canonical schema definitions that the generator, the official parser, and much of the surrounding tooling depend on.
The attack that hit those packages began with a well-documented class of GitHub Actions misconfiguration researchers call a "pwn request." One of AsyncAPI's workflows was set to trigger automatically whenever someone opened a pull request, a routine setup for running checks on incoming code. The problem was how it ran those checks: using the pull_request_target trigger, which grants the workflow full access to the repository's secrets while checking out and executing code from the pull request itself, code an outside contributor fully controls.
Researchers at Wiz, who published one of the first detailed technical breakdowns of the incident, found that the attacker's flood of near-identical pull requests was not random noise. It was camouflage. Automated review tools eventually flagged PR #2155's obfuscated payload as suspicious, but by the time anyone looked closely, the workflow had already run to completion and the token was gone.
A Known Bug Sat Unmerged for 58 Days
The vulnerability was not a surprise to everyone. A contributor had flagged the exact weakness months earlier, opening a proof-of-concept pull request on April 29 that demonstrated how an attacker could exploit the workflow. On May 17, the same contributor followed up with an actual fix, splitting the risky workflow into two separate jobs so that untrusted code would never run in the same context as the repository's secrets.
That fix sat open and unmerged for 58 days. The attack landed on day 59.
Once in possession of the stolen token, the attacker moved fast. At 6:58 a.m. UTC, they pushed a commit directly to the generator repository's next branch under a placeholder identity that read simply "Your Name," the kind of default value that fills in automatically when a developer never configures Git. That single push was enough. It triggered AsyncAPI's real, legitimate release workflow, which built and published the tainted code to npm using the project's official credentials, through npm's GitHub Actions integration known as trusted publishing.
That distinction matters. The attacker never had to steal an npm password or forge an authentication token. They compromised the GitHub side of the pipeline and let AsyncAPI's own trusted automation do the rest, which is why the malicious releases came bundled with valid SLSA provenance attestations, the cryptographic paperwork meant to prove a package was built by an authorized, auditable process. As Chainguard's researchers put it: the provenance proved where the package came from, not that the process producing it could be trusted at that moment.
None of the five malicious releases relied on npm's install, preinstall, or postinstall scripts, the mechanism nearly every prior npm supply chain attack has used to run code the moment a package lands on a machine. The timing looks deliberate. npm shipped its biggest security overhaul in 16 years just six days earlier, on July 8, specifically to block unapproved install scripts by default. The AsyncAPI payload sidestepped that defense entirely by hiding inside ordinary source files and firing only when the infected module was actually imported or required, the moment a build, a test suite, or a running application calls into the library during normal use.
Less than an hour after the first packages went live, the attacker pivoted to a second AsyncAPI repository that separately publishes @asyncapi/specs, pushing a new round of commits between 7:51 and 8:28 a.m. UTC. Two more malicious versions followed, the last one carrying the latest tag npm serves to anyone who installs the package without specifying a version.
Two Months of Warning, Four Hours of Damage
Millions of Downloads, One Credential-Stealing Payload
Once triggered, the injected code launched a hidden background process that quietly pulled a much larger, encrypted second-stage program from a decentralized file-sharing network, then ran it. Researchers who safely decoded that payload without executing it, including teams at Wiz, Socket, Aikido, and SafeDep, found a fully built remote access framework capable of collecting:
- Saved browser passwords and cookies from Chrome, Brave, Firefox, and Edge
- SSH private keys and configuration files
- npm, GitHub, and other developer authentication tokens
- AWS and other cloud provider credentials
- macOS Keychain entries
- Cryptocurrency wallet files
Beyond credential theft, the framework carried the ability to run arbitrary shell commands, maintain persistence across reboots, and reach its operators through at least six separate communication channels, from a conventional command server down to a peer-to-peer network and an Ethereum smart contract, so that blocking any single channel would not sever the connection. Researchers also found capabilities present in the code but switched off in this deployment: automatic spreading to other npm, PyPI, and Cargo packages, and a module built to inject instructions into AI coding assistants including Claude Code, Cursor, and GitHub Copilot.
The payload's internal code comments labeled it "M-RED-TEAM v6.4," while its configuration and file paths carried the branding of Miasma, a credential-stealing toolkit that circulated in earlier 2026 supply chain campaigns, including one that hit Red Hat's own npm packages through a separate trusted-publishing weakness. Researchers at OX Security and SafeDep, who compared the two toolkits in detail, found the underlying code, cryptography, and infrastructure differed enough that this was, at most, a rebrand or a parallel build rather than a direct reuse, leaving attribution genuinely unsettled.
Estimating exactly how many downloads were at risk depends on which source, and which hour of npm's live counters, you trust. Endor Labs, citing npm's own figures for the week ending July 11, put the combined total near 2.96 million, with @asyncapi/specs alone accounting for about 2.74 million. Aikido Security and the artifact-management vendor Cloudsmith independently arrived at figures close to 2.9 million. BleepingComputer, checking npm's live download counters a day after the packages were pulled, tallied a lower but still substantial 2.25 million.
| Package | Malicious version | Safe version |
|---|---|---|
| @asyncapi/generator | 3.3.1 | 3.3.0 |
| @asyncapi/generator-helpers | 1.1.1 | 1.1.0 |
| @asyncapi/generator-components | 0.7.1 | 0.7.0 |
| @asyncapi/specs | 6.11.2 and 6.11.2-alpha.1 | 6.11.1 |
Anyone who installed the affected versions during the exposure window should treat the environment as compromised. Recommended steps, drawn from the security firms that analyzed the malware, include:
- Pin every affected package to the safe version listed above and regenerate lock files
- Rotate npm, GitHub, and other developer tokens
- Rotate SSH keys and AWS or other cloud credentials
- Rotate saved browser passwords and cookies on any machine that ran the packages
- Audit CI/CD pipelines that ran during the exposure window and rotate any secrets they touched
Provenance Proved Origin, Not Trustworthiness
Chainguard called the July incident at least the third notable pwn-request-style GitHub Actions compromise of a high-download npm namespace in 2026 alone. The pattern recurs because it works. Earlier this year, the identical misconfiguration class let attackers compromise the security scanner Trivy, a breach that eventually reached deep into the AI infrastructure library LiteLLM and its roughly 95 million monthly downloads. In both cases, attackers skipped the registry entirely and went after the CI/CD pipeline that publishes to it, because a stolen GitHub credential can produce a package that looks, cryptographically, exactly like a legitimate release.
There is a harder irony sitting underneath this particular incident. AsyncAPI had already lived through a version of this scenario. Roughly eight months earlier, in November 2025, the project's npm packages carried malware from a second wave of the self-propagating Shai-Hulud worm, which compromised more than 24,000 repositories across the ecosystem that month alone. In its public postmortem afterward, AsyncAPI's team wrote that it planned to stop relying on long-lived npm tokens and move to npm's newer OIDC-based trusted publishing, tying package releases directly to a specific GitHub repository and workflow rather than a password that could leak or age past rotation.
That migration happened. It did not help. The July 2026 attacker never needed an npm token, because trusted publishing worked exactly as designed: it published whatever the authorized GitHub workflow told it to, and the authorized GitHub workflow had already been hijacked one layer up, through the pull_request_target hole nobody had closed. The fix for the last incident became the delivery mechanism for this one.
Cloudsmith, an artifact-management vendor, argued the deeper problem is structural rather than a single AsyncAPI mistake. In the hours right after publication, no security advisory yet named the new versions as malicious, so any team pulling @asyncapi/specs@latest straight from npm during that window would have received a clean result from every conventional scanner. Not because the tooling failed, but because nothing had positioned itself to catch a brand-new, freshly signed, correctly named package before it reached a developer's machine.
Not every researcher treated the malware's sophistication as proof of a well-resourced, professional operation. OX Security noted the payload checked whether it was running inside a virtual machine, whether common endpoint security tools were installed, and whether the system's language was set to Russian, terminating itself rather than run under any of those conditions. That kind of caution, alongside the dormant self-propagation code and the unused AI-assistant poisoning module, points to a toolkit built for a longer campaign than the one actually deployed on July 14.
The Bottom Line
Strip away the obfuscation and the multi-channel command infrastructure, and the AsyncAPI incident comes down to two plain facts. A known, previously reported vulnerability in a GitHub Actions workflow sat unpatched for 58 days. When someone finally exploited it, the project's own legitimate, cryptographically trusted publishing pipeline did exactly what it was built to do: it published what it was told to publish, no questions asked.
That is the uncomfortable lesson for every team that has adopted npm's trusted publishing, OIDC authentication, or SLSA provenance as a supply chain fix. Those tools solve a real problem. They make it much harder to forge or leak the credentials that publish a package. They do nothing to guarantee the pipeline feeding them has not already been compromised somewhere upstream, in a workflow file nobody has re-reviewed since the day it was written.
The pull request that would have prevented this attack existed for nearly two months before it happened. It just never got merged in time.
Sources
- M-Red-Team: AsyncAPI Supply Chain Compromise via GitHub Actions (Wiz Blog, July 14, 2026)
- Coordinated AsyncAPI Supply Chain Attack: Miasma RAT Delivered via Compromised CI/CD Pipelines in Two Repositories (StepSecurity, July 14, 2026)
- AsyncAPI supply chain compromise: npm packages backdoored via GitHub Actions "pwn request" (July 2026) (Chainguard, July 14, 2026)
- Compromised npm Packages in the AsyncAPI Namespace Deliver Miasma Botnet Loader (Socket.dev, July 14, 2026)
- AsyncAPI npm packages backdoored via GitHub Actions (Aikido Security, July 14, 2026)
- AsyncAPI npm organization compromised, 2M weekly downloads affected (OX Security, July 14, 2026)
- AsyncAPI Packages Compromised with Miasma RAT (SafeDep, July 14, 2026)
- Inside the AsyncAPI npm supply chain attack (Cloudsmith, July 14, 2026)
- Compromised AsyncAPI npm Packages Deliver Multi-Stage Botnet Malware (The Hacker News, July 15, 2026)
- AsyncAPI npm packages infected with credential-stealing malware (BleepingComputer, July 15, 2026)
- AsyncAPI npm Packages With 2M Weekly Downloads Compromised via GitHub Actions (Cyber Security News, July 14, 2026)
- How Unprotected Release Branches Let Attackers Compromise AsyncAPI (Endor Labs, July 2026)
- Shai-Hulud — What Happened, How We Fixed It, and What We Learned (AsyncAPI Initiative, November 26, 2025)