Alle Artikel

AsyncAPI supply chain compromise: npm packages backdoored via GitHub Actions "pwn request" (July 2026)

Quincy Castro, CISO

TL;DR

  • What happened: An attacker stole a privileged GitHub personal access token from AsyncAPI's CI through a misconfigured pull_request_target workflow, then used it to publish five trojanized versions across four @asyncapi npm packages on July 14, 2026.

  • Packages Affected: @asyncapi/generator, @asyncapi/generator-helpers, @asyncapi/generator-components, and @asyncapi/specs on npm.

  • Scale: Four packages, five malicious versions, a combined weekly download footprint in the low millions (estimates vary by source; see Affected packages below).

  • Risk: The payload installs a credential-stealing remote access trojan that targets browser passwords, SSH keys, npm and GitHub tokens, cloud credentials, and cryptocurrency wallets, and maintains an active command-and-control channel. It fires on require(), not on install.

  • Chainguard customers: Not affected. Chainguard uses multiple layers of defense to ensure malicious packages are unavailable for consumption. The builds failed a comparison against upstream source and were never published. Additionally, customers were protected via configurable cooldowns.

  • What to do: If you or your CI pulled any of the affected versions between 07:10 and 08:30 UTC on July 14, treat the environment as compromised and rotate credentials immediately.

On July 14, 2026, an attacker opened dozens of pull requests against the AsyncAPI generator repository, using the noise to camouflage PR #2155, which exploited a known class of GitHub Actions misconfigurations. Within an hour of stealing a service account's token, the attacker had pushed malicious commits that triggered AsyncAPI's own release pipeline, publishing five backdoored package versions carrying valid provenance signatures. Here's what we know about the attack, why Chainguard customers were not affected, and what every other team running these packages should do right now.

Affected packages

Five malicious versions across four packages, all published between 07:10 and 08:30 UTC on July 14, 2026:

From asyncapi/generator:

Package

Malicious version

Published (UTC)

Safe version

@asyncapi/generator

3.3.1

07:10:48

3.3.0

@asyncapi/generator-helpers

1.1.1

07:10:42

1.1.0

@asyncapi/generator-components

0.7.1

07:10:44

0.7.0

From asyncapi/spec-json-schemas, published roughly an hour later in a second wave:

Package

Malicious version

Published (UTC)

Safe version

@asyncapi/specs

6.11.2-alpha.1

08:06:20

6.11.1

@asyncapi/specs

6.11.2

08:30:09

6.11.1

All five versions were tagged as latest or alpha at the time of disclosure.

What the malware does

The malicious code lives in three legitimate-looking source files (validator.js, utils.js, and ErrorHandling.js) hidden behind hundreds of trailing whitespace characters, plus an unconcealed version prepended to index.js in the specs package. There is no preinstall, postinstall, or install script in any of the three package.json files. Instead, the payload fires on import/require(), the moment a build or CI job actually loads the library, not at install time.

Once executed, the payload settles in for the long haul. It steals credentials, plants a persistent backdoor, keeps multiple channels open back to the attacker, and — unlike a worm — stays contained to the machine it landed on. Here's what each of those looks like in practice:

  • Credential theft: Harvests saved browser passwords and cookies, SSH keys, npm and GitHub CLI tokens, cloud credentials, and cryptocurrency wallet data.

  • Persistence: Drops a second-stage payload as sync.js in a platform-specific application data directory and installs a systemd user service on Linux.

  • Command and control: The malware has four separate ways to reach the attacker, so blocking one doesn't cut it off: plain HTTP requests to the attacker's server, messages relayed through Nostr (a decentralized messaging network), instructions read from an Ethereum smart contract, and a peer-to-peer network connecting infected machines to each other. Once connected, it can receive commands to list files on the machine and steal data.

  • Scope: Functions as a full remote access toolkit rather than a self-propagating worm, meaning the victim does not become an attacker.

Indicators of compromise

If you installed any affected version (see Affected packages above), treat your environment as compromised. Here’s what to look for:

Network indicators:

  • 85.137.53.71 (ports 8080, 8081)

  • ipfs[.]io (payload delivery)

  • rentry.co (token exfiltration dead-drop)

File hashes (SHA1):

  • 22bf76fe317ea6769bd38619bd440e42d119bd6bvalidator.js

  • a7e18d96efd3cdb127ef4cdcad9e3ad26c482bf2utils.js

  • 9890950adcbc2478e7a080234f053214adbad44eErrorHandling.js

  • c70e105e212ff3c1daa04bb2a62507717f296b0bindex.js

  • c8cb3f6d5b90c46686d2bf531dc1a5786e27edc5sync.js Stage 2

Package-level indicators: the five package@version pairs listed above.

Other artifacts: dropped file at ~/.local/share/NodeJS/sync.js (Linux), ~/Library/Application Support/NodeJS/sync.js (macOS), or %LOCALAPPDATA%\NodeJS\sync.js (Windows); systemd unit miasma-monitor.service.

How to check if you're affected

List installed versions:

npm ls @asyncapi/generator @asyncapi/generator-helpers @asyncapi/generator-components @asyncapi/specs

Grep lockfiles:

grep -R '"@asyncapi/generator": "3.3.1"' package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
grep -R '"@asyncapi/specs": "6.11.2"' package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

Check for the dropped payload:

ls -la ~/.local/share/NodeJS/sync.js 2>/dev/null
ls -la ~/Library/Application\ Support/NodeJS/sync.js 2>/dev/null
dir "%LOCALAPPDATA%\NodeJS\sync.js"

A lockfile match alone warrants investigation, even if the payload file isn't present, since the trigger is import/require, not install.

Immediate steps if you're affected

  1. Downgrade immediately: pin to @asyncapi/generator@3.3.0, @asyncapi/generator-helpers@1.1.0, @asyncapi/generator-components@0.7.0, and @asyncapi/specs@6.11.1, and verify with npm ls.

  2. Remove the dropped payload at the platform-specific path before rotating credentials, and kill any orphaned detached node processes.

  3. Rotate exposed credentials: npm tokens, GitHub tokens and CLI config, SSH keys, cloud (AWS, GCP, Azure) credentials, and browser-saved passwords, in that order.

  4. Audit CI/CD: any pipeline that ran npm install or imported these packages during the compromise window should have its secrets rotated and be treated as compromised.

  5. Block egress to 85.137.53.71 and monitor for outbound traffic to IPFS gateways and rentry[.]co from build infrastructure.

Why Chainguard customers were not affected

Chainguard uses multiple layers of defense to ensure malicious packages are unavailable for consumption. When building from source, Chainguard-built versions must match the upstream source repo in a static analysis test. These tests failed for the compromised packages (by design), which prevented them from being served to customers.

Additionally, customers can use a cooldown and malware scanning as an added layer of protection against malware.

The bigger picture

This is at least the third notable "pwn request"-style GitHub Actions compromise of a high-download npm namespace in 2026, and the second to touch the AsyncAPI organization this year. 

There are three things worth noting.

  1. The vulnerable workflow pattern here had already been flagged internally fifty-eight days before the attack, with a fix sitting unmerged.

  2. The payload achieved valid Sigstore and SLSA provenance because the attacker compromised the CI identity rather than an npm token directly, a reminder that provenance proves where a package came from, not that its source was trustworthy at the time.

  3. The underlying flaw was a pull_request_target trigger paired with a checkout of untrusted pull request code, the same vulnerability class behind the March 2025. tj-actions/changed-files compromise, which leaked secrets from over 23,000 repositories.

Sources

Want to learn more about Chainguard?

Supply chain attacks like this one are getting faster, more automated, and harder to catch. Chainguard Libraries allows your team to turn off live access to npm, PyPI, and Maven Central and replace it with secure-by-default endpoints from Chainguard. Our dependency catalog has multiple layers of security controls, including building from source, malware scanning, cooldowns, and other policies to prevent malware and packages that don’t meet your organization’s standards from entering your builds.

Get in touch with our team to learn more.

Share this article

Verwandte Artikel

Want to learn more about Chainguard?

Contact us