AsyncAPI npm Packages Poisoned via Malicious PR

Microsoft Security · High sophistication
Last updated July 30, 2026

Attackers compromised the @asyncapi npm organization by abusing a misconfigured GitHub Actions workflow, then republished multiple AsyncAPI-related packages with a hidden loader. The malware ran automatically when the poisoned packages were imported (not during install), pulled a second-stage payload from IPFS, and connected to command-and-control infrastructure. This incident could expose developer machines and CI/CD environments that built or ran code during the brief exposure window.

How the attack worked

The compromise began not with a stolen credential but with a pull request. Attackers submitted a PR to the asyncapi/generator repository that targeted a docs-preview automation workflow. That workflow used pull_request_target while also checking out the untrusted head commit of the PR, combining two unsafe choices that placed attacker-controlled code inside the base repository's privileged security context. The submitted content was designed to fetch and evaluate remote JavaScript, giving the attacker a foothold to eventually publish poisoned versions of AsyncAPI-related npm packages.

From there, five versions across four packages were republished with a hidden loader. When any downstream build or application imported one of these packages, the injected code ran immediately, spawning a child process that downloaded a second-stage payload, sync.js, from a public IPFS gateway and connected to command-and-control infrastructure.

Why it succeeded

Several factors let this campaign slip past common defenses. The malicious code executed at module-load (import/require) time rather than during install, so the widely used npm install --ignore-scripts mitigation had no effect. The poisoned packages were also published through the project's legitimate GitHub Actions OIDC release workflow, which meant the resulting artifacts carried valid provenance signatures accurately tied to the real repository, commits, and workflow, even though the triggering commits themselves were unauthorized. This shows that verified publishing pipelines and signed provenance can still carry compromised code if the upstream automation is manipulated.

What to watch for

  • A pull request that triggers a privileged workflow using pull_request_target while checking out untrusted PR code
  • Documentation or content files that attempt to download and evaluate remote JavaScript
  • Unexpected detached Node.js child processes appearing during builds or application startup
  • Network connections to IPFS gateways or unfamiliar IP addresses and ports
  • New directories masquerading as legitimate Node.js paths containing unexpected files like sync.js

Building resistance

Teams that build or maintain open source tooling should treat pull request automation as a high-risk entry point and avoid running untrusted PR code with access to secrets or privileged tokens. Because valid provenance does not guarantee a safe build, organizations should monitor for import-time execution patterns and unusual child processes rather than relying solely on install-time protections. If a build system or developer workstation imported a compromised version, credentials and secrets should be rotated from a clean host, and npm and Yarn caches should be purged along with a search for the sync.js artifact across affected environments.

Key findings

  • Microsoft observed a coordinated supply-chain compromise of the @asyncapi npm organization affecting five versions across four packages.
  • The campaign executed at module-load time (import/require), so "npm install --ignore-scripts" would not prevent execution.
  • The initial entry point was a malicious GitHub pull request that triggered a privileged workflow using pull_request_target and checked out untrusted PR code.
  • The malware fetched a second stage (sync.js) via IPFS and enabled C2 and persistence; credential-harvesting modules existed but were disabled in the analyzed build.
  • C2 infrastructure included 85.137.53[.]71 on ports 8080, 8081, and 8091; defenders were advised to hunt for sync.js and purge npm/Yarn caches.

Who’s being targeted

  • Commonly targeted roles: Developers, DevOps, Build/Release Engineering, Open Source Maintainers, Security Engineering.
  • Affected industries: Software development, DevOps / CI/CD operations, Open source project maintainers, Any organization building Node.js/AsyncAPI tooling.
  • Attack channels: github, website.
  • Impersonated: Open-source contributor (external), Legitimate npm package release (trusted publishing).

Red flags to watch for

  • Workflow uses pull_request_target and checks out untrusted PR code in the base repo security context
  • Docs/MDX content attempts to download and evaluate remote JavaScript
  • Workflow steps can access secrets or a broadly privileged token
  • Unexpected detached Node.js child process during builds or app startup
  • Network calls to IPFS gateways and unknown C2 IP/ports
  • New 'NodeJS' directories and a sync.js file written under user/app-data paths
Try Mirage

Mirage safely runs attacks like this one against your own team, so you find out what happens before a real adversary does.

Get a demo

Frequently asked questions

How did attackers compromise the AsyncAPI npm packages?

A malicious pull request targeted a docs-preview workflow that used pull_request_target and checked out untrusted PR code, giving the attacker's content access to the base repository's security context and enabling code execution.

Does npm install --ignore-scripts protect against this attack?

No. The malware executed at module-load time when the package was imported or required, not during install, so the common --ignore-scripts mitigation did not prevent it.

Were the poisoned packages still cryptographically signed?

Yes. The legitimate GitHub Actions OIDC release workflow published the poisoned packages with valid provenance signatures, even though the underlying commits were unauthorized.

What should teams do if they imported an affected package?

Remove all affected versions, purge npm and Yarn caches, hunt for the sync.js payload, and rotate credentials from a clean host since second-stage execution can expose tokens.

Read the video transcript

Imagine this: you just import an AsyncAPI package… and that import is what pops a shell on your build server. In the AsyncAPI incident, a malicious GitHub pull request hit a docs-preview workflow using pull_request_target, checked out untrusted PR code, then published poisoned npm packages with valid provenance under npm-oidc-no-reply@github.com. Here’s the twist: these packages don’t fire on install. When your app imports them, hidden code spawns a Node.js child process, pulls sync.js from IPFS, and quietly talks to 85.137.53.71 over ports like 8080 and 8081. If your builds or workstations ever pulled a compromised AsyncAPI version, treat it like secrets are exposed: from a clean machine, rotate your tokens and credentials. That’s the move.

Similar attacks

Invoice Phish Leads to Resilient ValleyRAT

Invoice Phish Leads to Resilient ValleyRAT

A Japanese industrial manufacturer was targeted by the SilverFox group using an invoice-themed phishing email that kicked off a multi-stage malware chain. The…

July 31, 2026