Date Observed: July 14, 2026
Ecosystem: npm (@asyncapi organization)
Targets: Developers, CI/CD runners, and build systems consuming AsyncAPI packages
Attack Type: CI/CD compromise via GitHub Actions pull_request_target -> trojanized package publish
Impact: 5 malicious versions across 4 packages, ~2.9M combined weekly downloads; import-time Miasma RAT delivery
Key Takeaways
- Attackers backdoored four @asyncapi npm packages by abusing a misconfigured GitHub Actions workflow, not by stealing a npm token directly.
- The malicious code runs at import/require() time, so npm install –ignore-scripts provides no protection.
- The payload is Miasma-family malware, observed in this campaign primarily as a multi-stage, cross-platform RAT that fetches its loader from IPFS and beacons to hardcoded C2 infrastructure.
Introduction
On July 14, 2026, an attacker published trojanized versions of four packages in the @asyncapi npm organization. The compromise did not begin at npm. It began in a GitHub Actions workflow that granted repository secrets to attacker-controlled pull request code, a class of misconfiguration known as a “pwn request.”
The affected packages carry roughly 2.9 million combined weekly downloads, most concentrated in @asyncapi/specs. The injected payload was Miasma, a modular remote access trojan that executes when a developer or CI runner imports the poisoned module rather than when the package installs.
Scope and Impact of the Attack
Five malicious versions were published across four packages. Each has a known-safe prior version:
- @asyncapi/generator@3.3.1 (safe: 3.3.0)
- @asyncapi/generator-helpers@1.1.1 (safe: 1.1.0)
- @asyncapi/generator-components@0.7.1 (safe: 0.7.0)
- @asyncapi/specs@6.11.2 and 6.11.2-alpha.1 (safe: 6.11.1)
According to Aikido’s analysis, @asyncapi/specs alone accounts for roughly 2.7 million of the 2.9 million weekly downloads, making it the primary blast radius. The malicious versions were live for a limited window. StepSecurity reports exposure windows ranging from 2 hours 48 minutes to 4 hours 3 minutes before all five versions were unpublished around 11:18 UTC.
How the Attack Works
The attack chained a CI/CD misconfiguration into a trusted-publish pipeline, then delivered malware at import time.
Stage 0 – Credential theft via pwn request
At 05:08 UTC the attacker opened 37 pull requests against asyncapi/generator. One contained obfuscated JavaScript that ran in a workflow using pull_request_target, a trigger that executes with access to repository secrets. The workflow checked out the attacker’s code rather than the base branch, exfiltrating the release bot’s token. Wiz reports the vulnerability had been identified with a proof-of-concept on April 29 and a fix proposed on May 17 that remained unmerged.
Stage 1 – Riding the release pipeline
The attacker pushed malicious commits to the next branch at 06:58 UTC. This triggered the legitimate release-with-changesets.yml workflow, which published the packages through GitHub’s OIDC trusted-publisher system. Per JFrog’s research, the malicious packages carried valid npm provenance / SLSA-style attestations, because they were published through the legitimate GitHub Actions pipeline. Three generator packages published at 07:10 UTC; the two specs versions followed at 08:06 and 08:30 UTC.
Stage 2 – Import-time execution
The injected code sits inside legitimate source files, not in an install hook. When the module loads, it spawns a detached Node.js process that downloads an encrypted loader (sync.js) from IPFS and decrypts the final Miasma framework. Microsoft’s write-up notes that because the trigger is require() or import, npm install –ignore-scripts offers no protection. The attack did not need an install hook, but it did need the poisoned module to be loaded by developer tooling, a build process, or an application path.
Propagation and Persistence
Miasma drops sync.js into a NodeJS-masquerading directory that varies by platform: ~/.local/share/NodeJS/sync.js on Linux, ~/Library/Application Support/NodeJS/sync.js on macOS, and %LOCALAPPDATA%\NodeJS\sync.js on Windows. It establishes persistence through a miasma-monitor.service systemd unit, shell startup files, or a Windows Run registry key.
Key Capabilities
The framework harvests browser passwords, SSH keys, npm and GitHub tokens, AWS credentials, and cryptocurrency wallets when enabled. It beacons to the hardcoded C2 server 85.137.53.71 on ports 8080, 8081, and 8091, and maintains fallback channels including IPFS, Nostr relays, Ethereum smart contracts, and BitTorrent DHT nodes for resilience.
Why this Matters to DevOps and DevSecOps Teams
This compromise defeats several controls that teams commonly rely on. The packages were signed with valid provenance, so attestation checks passed. The payload avoids install hooks, so –ignore-scripts did nothing. And the root cause lived in CI/CD configuration, an area often outside the scope of dependency scanners.
Why Existing Controls Miss This
Software composition analysis (SCA) identifies packages, versions, and their known risks, so a scanner has no way to flag a freshly published version as malicious in the hours before detection. Lockfile pinning does help here: teams already pinned to a safe version with npm ci would not have pulled the trojanized releases. But pinning only protects that subset. It offers nothing the moment a developer runs npm install, bumps the dependency, or builds without a committed lockfile, which is exactly when a freshly weaponized version gets consumed. The damage in this attack, the IPFS loader pull, the C2 beacon, and the credential exfiltration, are all runtime network actions inside the build. That is the layer most pipelines leave uncontrolled.
How InvisiRisk Protects Against This Attack
InvisiRisk operates as a Build Application Firewall (BAF) inside the CI/CD pipeline, enforcing policy on build-time behavior. Against Miasma-class attacks, these capabilities apply directly.
Build Proxy / Network Interception. InvisiRisk operates as a network proxy inside the build environment and can enforce policy on all outbound traffic. The Stage 2 IPFS retrieval of sync.js and the C2 callbacks to 85.137.53.71 are outbound connections to unapproved destinations. Under allowlist-based egress policy, they are blocked before the loader ever reaches the runner. This same control underpins our CI/CD security for DevOps teams.
Stability Buffer. The malicious versions were live for under four hours before unpublishing. With a 48-hour stability buffer, InvisiRisk blocks newly published packages before they can be consumed in a build, so a version published at 07:10 UTC and pulled at 11:18 UTC would never enter a protected build. This mirrors the defense described in our coverage of the Miasma attack on Red Hat cloud services.
Why Build-Time Defenses Matter
This attack proved that valid provenance and clean install scripts are not enough when the malicious behavior is a runtime network call. Build-time egress enforcement is the control layer that sees that call and stops it. For any team importing from public registries into privileged CI/CD runners, the question is not whether a trusted package can be weaponized, but whether your pipeline can block the callback when it is.


