Four AsyncAPI npm Packages With 2.9 Million Weekly Downloads Compromised


Attackers compromised four npm packages in the @asyncapi namespace and published five malicious versions containing a cross-platform remote-access implant. The affected packages collectively receive about 2.9 million downloads per week.

The malicious code targeted developer workstations, build servers, and CI/CD environments running Windows, macOS, or Linux. It executed when an affected module loaded, meaning a normal import or require operation could begin the infection chain without an npm installation script.

Aikido Security’s AsyncAPI investigation found that the first-stage code downloaded an encrypted Node.js payload from IPFS, saved it as sync.js, and started it as a detached background process.

Four packages and five versions contained malware

The attackers compromised two AsyncAPI repositories. Malicious changes in the asyncapi/generator repository reached three packages, while changes in asyncapi/spec-json-schemas produced two poisoned releases of @asyncapi/specs.

The affected packages have a combined weekly download footprint of approximately 2.9 million. Aikido estimated that @asyncapi/specs alone accounts for around 2.7 million weekly downloads.

PackageMalicious versionKnown clean versionApproximate weekly downloads
@asyncapi/specs6.11.26.11.1About 2.7 million
@asyncapi/specs6.11.2-alpha.16.11.1Included above
@asyncapi/generator3.3.13.3.0About 126,000
@asyncapi/generator-helpers1.1.11.1.0About 45,000
@asyncapi/generator-components0.7.10.7.0 or a later verified clean releaseAbout 46,000

All five malicious releases were removed from the npm registry on July 14. Fresh installations resolved to clean versions after their removal, but existing lockfiles, caches, containers, internal mirrors, and installed dependencies may still contain the compromised code.

A vulnerable GitHub Actions workflow provided initial access

The attack began with a GitHub Actions workflow in the AsyncAPI generator repository. The workflow used the pull_request_target event and checked out code submitted through an external pull request.

This combination can expose secrets and elevated repository permissions to attacker-controlled code. GitHub’s workflow trigger documentation warns that running untrusted code under pull_request_target can grant unintended access to secrets or write privileges.

A contributor had submitted a fix for the vulnerable workflow on May 17, 2026. The pull request remained unmerged when attackers exploited the weakness nearly two months later.

Attackers hid the malicious pull request among spam

Attackers opened dozens of pull requests against the AsyncAPI generator repository early on July 14. Most appeared to add donation files, creating noise around the malicious submission.

Pull request 2155 triggered the vulnerable documentation-preview workflow at approximately 05:11 UTC. The submitted code loaded a second stage from rentry.co and ran it inside the privileged CI environment.

Datadog Security Labs found that the CI-stage malware searched running process environments for GitHub and Netlify credentials. It then sent collected values to an attacker-controlled Rentry page.

Evidence points to stolen repository access, not an npm token

Aikido reported that the attacker stole an npm publishing token. Other researchers reached a different conclusion after examining the npm provenance records.

According to StepSecurity’s AsyncAPI analysis, the packages were published through AsyncAPI’s legitimate GitHub Actions workflows using npm’s OIDC trusted-publisher integration. StepSecurity found no need for a stolen npm token.

The attacker appears to have obtained a privileged GitHub credential associated with the AsyncAPI automation account. That access allowed malicious commits to reach protected release branches and trigger authorized publishing workflows.

Valid provenance did not mean the code was safe

The poisoned releases carried valid npm provenance attestations because AsyncAPI’s authorized GitHub Actions workflows built and published them. The attestations correctly linked the packages to the project’s repositories, workflows, commits, and release branches.

However, provenance could not determine whether the commits themselves were legitimate. It confirmed which trusted workflow produced each package, not whether an attacker had gained permission to push the source code.

This distinction matters for software supply-chain security. Signed packages and provenance records reduce some forms of tampering, but they cannot protect a release when attackers compromise the trusted source repository or publishing workflow.

Malware executed when applications imported the packages

The attacker did not use preinstall, install, or postinstall lifecycle scripts. Instead, malicious code appeared inside ordinary runtime files used for schema exports, validation, utility functions, and error handling.

A simple require or import operation could launch the downloader. This design allowed the packages to avoid defenses that block npm lifecycle scripts while still infecting systems during builds, tests, documentation generation, or normal application startup.

The first stage launched an obfuscated Node.js command as a detached process. It then retrieved one of two encrypted objects from IPFS, depending on which package family initiated the infection.

The payload installed a persistent remote shell

The downloaded IPFS object contained an encrypted loader measuring more than 8 MB. After decryption, it launched a larger third-stage framework containing remote-shell, persistence, credential-harvesting, propagation, and peer-discovery capabilities.

The recovered malware analysis found that credential harvesting, reconnaissance, and package propagation existed in the code but were disabled in the observed configuration. Persistence and remote-shell execution remained active.

This difference does not make an infected host safe. The implant contacted its command server approximately every 30 seconds and could execute shell commands supplied by its operator. Attackers could use that access to collect credentials, modify files, install other malware, or move deeper into a network.

Payload used different storage paths on each operating system

The downloader saved sync.js in a per-user directory designed to resemble normal Node.js application data.

Operating systemPayload locationPersistence method
Windows%LOCALAPPDATA%\NodeJS\sync.jsRegistry Run value named miasma-monitor
macOS~/Library/Application Support/NodeJS/sync.jsCommand added to .zshrc, .bashrc, or .bash_profile
Linux~/.local/share/NodeJS/sync.jssystemd user service named miasma-monitor.service

The Linux service may fail because its ExecStart instruction lacks a shell wrapper. However, the service file and related artifacts remain useful signs of attempted compromise.

The malware also generated a cryptographic identity and created a lock file to prevent multiple copies from running simultaneously.

Command server used unencrypted HTTP

The implant connected to 85.137.53.71 on port 8080 over HTTP. It sent signed and encrypted beacons containing limited host information and waited for commands.

Commands normally arrived in encrypted envelopes. However, the code also accepted a plaintext command array when an encrypted bundle was absent. Because the server connection used HTTP, a suitably positioned network attacker could potentially inject commands into an infected host.

The active shell passed commands to Node.js child_process.exec. Its only configured command blacklist entry was killall, leaving broad command-execution capability available to the operator.

Indicators of compromise

Security teams should search developer systems, CI runners, build containers, and internal package mirrors for affected versions and associated artifacts.

TypeIndicatorDescription
C2 server85.137.53.71:8080HTTP beacon and command channel
Additional ports85.137.53.71:8081 and 85.137.53.71:8091Upload and proxy-management services
IPFS CIDQmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyfSpecs-family encrypted loader
IPFS CIDQmQobZSp1wRPrpSEQ56qnyq7ecZh5Bg5k1fnjt4SUwwHb9Generator-family encrypted loader
Dropped filesync.jsLoader placed in a per-user NodeJS data directory
Lock file~/.config/.miasma/run/node.lockPrevents multiple implant instances
Linux persistencemiasma-monitor.servicesystemd user service
Windows persistencemiasma-monitorRegistry Run value
Token exfiltrationrentry.coUsed during the GitHub Actions compromise
Ethereum contract0x12c37A86a0Ed0beBe5d1d6a43E42f07860eAc710Fallback service-address infrastructure

The Datadog incident report also recommends checking network records for the command server and IPFS payload locations. Organizations should preserve logs and volatile evidence before removing files from suspected systems.

How affected organizations should respond

Finding a malicious version in a lockfile or cache does not prove that the malware executed. The infection began when an application loaded the affected module. Teams should determine whether builds, tests, scripts, or applications imported the package during the exposure window.

If a system loaded one of the packages, organizations should treat the host as compromised. Removing the npm package or deleting sync.js cannot prove that the attacker did not run additional commands or install another persistence mechanism.

Immediate response steps include:

  • Remove all five malicious versions from manifests, lockfiles, package caches, internal mirrors, build images, and containers.
  • Reinstall a known clean version or a later version independently verified as safe.
  • Isolate systems that imported the affected packages.
  • Preserve running-process details, network connections, memory, and security logs.
  • Search for sync.js, miasma-monitor artifacts, identity files, and the implant lock file.
  • Review connections to the known command server, IPFS gateways, Nostr relays, Ethereum RPC services, and BitTorrent DHT nodes.
  • Rebuild compromised developer workstations and CI runners from trusted images.

Rotate credentials from a clean system

The implant contained a working remote shell, so defenders should assume that secrets accessible to an infected process may have been exposed. This includes credentials that the disabled automatic harvesting modules did not collect.

Organizations should rotate the following from a separate, verified-clean computer:

  • GitHub access tokens and Git credentials.
  • npm publishing and automation tokens.
  • CI/CD secrets and deployment credentials.
  • AWS, Azure, Google Cloud, and other cloud credentials.
  • SSH keys and code-signing keys.
  • Netlify and hosting-platform tokens.
  • Browser sessions and saved application credentials.
  • Secrets stored in environment variables or local configuration files.

StepSecurity reported that the malicious releases have been removed from npm. Existing installations still require investigation because unpublishing a package does not remove it from developer machines, lockfiles, caches, or private registries.

GitHub Actions workflows need stricter trust boundaries

Repository owners should audit every workflow using pull_request_target, workflow_run, issue_comment, or other events that may combine untrusted input with elevated permissions.

GitHub advises maintainers not to build or run untrusted pull-request code in a pull_request_target workflow. Its GitHub Actions guidance recommends using the trigger only for safe operations such as labeling or commenting when possible.

Projects should apply least-privilege permissions, protect publishing branches, require verified reviews, restrict automation tokens, and alert on unexpected pushes from service accounts. Provenance should remain one layer of defense, but teams must also protect the source code and workflows that provenance identifies as trusted.

FAQ

Which AsyncAPI npm packages were compromised?

The compromised packages were @asyncapi/specs, @asyncapi/generator, @asyncapi/generator-helpers, and @asyncapi/generator-components. Attackers published five malicious versions across these four packages.

Does installing an affected package automatically infect a system?

The malicious code ran when an application imported or required the affected module. Installation alone may not have executed it, but teams must check whether builds, tests, scripts, or applications loaded the package.

Are the malicious AsyncAPI versions still available on npm?

Researchers reported that all five malicious versions were unpublished on July 14, 2026. Copies may remain in lockfiles, package caches, private registries, containers, and existing installations.

What should organizations do if an affected package executed?

They should isolate the system, preserve evidence, hunt for malware artifacts, rotate accessible credentials from a clean machine, and rebuild the affected workstation or server from a trusted image.

Why did npm provenance not stop the attack?

The packages came from AsyncAPI’s legitimate GitHub Actions publishing workflows, so their provenance records were valid. Provenance confirmed which workflow produced the packages but could not determine that an attacker had pushed the source commits.

Readers help support VPNCentral. We may get a commission if you buy through our links. Tooltip Icon

Read our disclosure page to find out how can you help VPNCentral sustain the editorial team Read more

User forum

0 messages