On July 14, 2026, five packages from the widely used @asyncapi npm organization were infected with malware that springs to life the moment any application loads them. This isn’t the usual postinstall treachery: the attack triggers at import time, making the common npm install --ignore-scripts defense completely ineffective. If your project or CI pipeline pulled in one of the compromised versions, simply running a build, test, or generator command would have unleashed the payload.

Microsoft Threat Intelligence disclosed the breach on July 15, confirming that the attacker hijacked a GitHub Actions workflow to push malicious code, then rode the project’s legitimate release machinery to distribute the poisoned packages under a trusted identity. The incident is a stark reminder that supply-chain attacks are evolving faster than the safeguards we lean on—and this time, the blast radius includes any Windows developer workstation, build runner, or container that imported an affected module.

The five poisoned packages roamed npm for hours

The attack spanned four package names and five distinct versions, all published within a 90-minute window:

Package Malicious Version Injection Point
@asyncapi/specs 6.11.2-alpha.1, 6.11.2 index.js
@asyncapi/generator 3.3.1 lib/templates/config/validator.js
@asyncapi/generator-components 0.7.1 lib/utils/ErrorHandling.js
@asyncapi/generator-helpers 1.1.1 src/utils.js

The stable 6.11.2 release of @asyncapi/specs contained a byte-identical malicious payload to the alpha version, and Microsoft observed a downstream Yarn cache fetching it by 08:49 UTC—just 19 minutes after publication. Because @asyncapi/specs is a transitive dependency of many AsyncAPI tools, the reach of this compromise extends far beyond anyone who intentionally installed a generator or component.

The loader embedded in each file spawns a hidden, detached Node.js child process that fetches a second-stage payload named sync.js from IPFS. On Windows, that file lands in %LOCALAPPDATA%\NodeJS\sync.js—a masquerade directory designed to look like a benign development artifact. From there, the script decrypts an 8.2 MB modular runtime Microsoft identifies as Miasma, which establishes encrypted command-and-control (C2) channels to 85.137.53[.]71 on ports 8080, 8081, and 8091, and installs persistence via a miasma-monitor Run registry key.

Your project didn’t need to install anything; it just had to be running

Traditional npm supply-chain attacks lean on lifecycle hooks like postinstall, which execute only during package installation. That’s why many security guides recommend --ignore-scripts. This campaign bypasses that entirely. The malicious code is injected directly into the module’s entry point—files that Node.js runs the instant you require() or import the package.

For a Windows developer, that means hitting npm test in a project that depends on AsyncAPI tooling could trigger the payload, even if the tainted package had been installed days earlier. The same goes for CI runners: a build that simply imports an affected module during a test or code-generation step would spawn the hidden child process. And because the malware’s credential-harvesting modules are present (though disabled in this observed build), any environment where the second stage ran must be treated as potentially exposed.

The attack also subverts the notion of provenance. All five packages carried valid npm provenance attestations, because the attacker pushed malicious commits that the repository’s own GitHub Actions OIDC workflow then built and published. The signed statement correctly says, “This package came from a legitimate workflow in the asyncapi repo”—but it doesn’t tell you that the commit itself was authored by an intruder. Trusting provenance alone would have given a false sense of security.

How a misconfigured GitHub Actions workflow opened the door

The breach began with a pull request (PR #2155) against asyncapi/generator. The repository used a docs-preview workflow triggered by pull_request_target, a dangerous event that runs in the context of the base repository and can access secrets. Worse, the workflow checked out the untrusted PR code. The attacker’s committed MDX file contained obfuscated JavaScript that fetched a remote payload from rentry[.]co and executed it, likely exfiltrating the asyncapi-bot personal access token.

With that token, the attacker pushed new commits to auto-publish branches. The legitimate release-with-changesets.yml and if-nodejs-release.yml workflows then published the five poisoned packages under the npm identity npm-oidc-no-reply@github[.]com, using GitHub OIDC trusted publishing. No npm credentials were stolen; the attacker simply slipped into the existing release pipeline.

Microsoft’s timeline shows the attacker-controlled commit at 05:08 UTC, the first three generator-family packages republished around 07:10 UTC, and the two @asyncapi/specs versions at 08:06 and 08:30 UTC. A prior proof-of-concept had flagged the workflow vulnerability on April 29, and a mitigation proposal was still under review when the incident occurred.

What you must do right now

If you or your team use any AsyncAPI packages—or consume projects that depend on them—treat this as an incident. Even if you never intentionally installed a compromised version, a transitive dependency or a shared cache could have pulled it in.

1. Scour your dependency trees for the bad versions
Search package-lock.json, yarn.lock, pnpm-lock.yaml, and any internal registries or artifact stores for these exact versions:

  • @asyncapi/specs 6.11.2-alpha.1 or 6.11.2
  • @asyncapi/generator 3.3.1
  • @asyncapi/generator-components 0.7.1
  • @asyncapi/generator-helpers 1.1.1

If you find any of them, consider the host compromised. Pin known-good versions: @asyncapi/specs ≤6.11.1, @asyncapi/generator 3.3.0, @asyncapi/generator-components 0.7.0, @asyncapi/generator-helpers 1.1.0.

2. Purge your package caches
Simply downgrading the dependency isn’t enough. npm and Yarn caches can reintroduce the poisoned tarball during future installs. On every affected machine, run:

npm cache clean --force
yarn cache clean

For CI runners and container build caches, delete and recreate the cache directories, and rebuild base images from a known-good snapshot.

3. Hunt for the malware on Windows endpoints
Check for the dropped file:

Test-Path $env:LOCALAPPDATA\NodeJS\sync.js

Look for persistence in the Registry:

Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" | Where-Object { $_ -like "*miasma-monitor*" }

Review process creation logs for hidden node.exe child processes, especially those with command lines referencing IPFS CIDs or the _0x5af5e1 obfuscation pattern. Microsoft Defender Antivirus detects the artifacts as Trojan:JS/MiasmStealer.SC and Trojan:Script/Supychain.A, but a clean scan isn’t sufficient to declare a host safe—the second stage may have run before detection updated.

4. Rotate every secret the environment could touch
Assume any credential accessible to a compromised build or workstation was exposed. Prioritize:

  • npm tokens (NPM_TOKEN, NODE_AUTH_TOKEN)
  • GitHub personal access tokens and GITHUB_TOKEN (check all repos the CI had access to)
  • Cloud provider keys (AWS, Azure, GCP)
  • Docker registry credentials
  • Kubernetes service account tokens
  • SSH keys (id_rsa, id_ed25519)
  • Vault tokens and .npmrc files

Perform the rotation from a clean host after the compromised machine is isolated. If GITHUB_TOKEN was present, the attacker could enumerate repositories and workflows.

5. Block known indicators at your network edge
If you don’t rely on IPFS for business operations, block public gateways (ipfs.io, dweb.link, cloudflare-ipfs.com). Also block outbound connections to 85.137.53[.]71 on ports 8080, 8081, and 8091. This reduces the chance of second-stage callbacks, though the malware’s decentralized fallback mechanisms (Nostr, Ethereum, BitTorrent DHT) make total containment difficult.

6. Adopt a release-delay strategy going forward
Update to npm CLI v11.10.0 or later, which supports the min-release-age configuration. Setting a delay (e.g., npm config set min-release-age 1h) won’t protect against a determined attacker, but it can give security teams and registry maintainers a head start before a new malicious version is locked into CI pipelines. Combine this with dependency pinning and lockfile auditing.

The harder lesson for the entire ecosystem

The AsyncAPI incident isn’t just another npm supply-chain headline. It demonstrates that even a well-intentioned CI/CD pipeline with trusted publishing can be subverted when workflow protections fail. The attack chain—pull_request_target with checkout, token theft, authorized commits, legitimate OIDC publish—is a blueprint that other projects must now defend against.

For Windows administrators and developers, the immediate focus is on finding any foothold the malware may have left behind. But the broader message is that security must shift left into the release workflows themselves. Review every GitHub Actions job that runs in a privileged context. Narrow bot token scopes. Gate releases behind protected environments and manual approvals. And never, ever check out untrusted code in a workflow that has access to secrets.

Microsoft continues to update detections in Defender for Endpoint and the XDR suite, and the AsyncAPI maintainers are working to harden their workflows. Watch for updates to the known-good version list and any additional impacted packages as the investigation unfolds.