Skip to content

Back to the catalog

M-Red-Team: AsyncAPI Supply Chain Compromise via GitHub Actions
wiz.iowriteup

M-Red-Team: AsyncAPI Supply Chain Compromise via GitHub Actions

Wiz Research details how an attacker used 37 decoy pull requests to mask exploitation of a pull_request_target "pwn request" misconfiguration in the asyncapi/generator GitHub Actions workflow, stealing a privileged PAT belonging to the asyncapi-bot service account. The attacker then published four malicious npm packages (five versions) under the @asyncapi namespace with over 3 million weekly downloads, delivering a self-identified "M-RED-TEAM v6.4" multi-stage payload that fetches an 8.25MB encrypted bundle from IPFS and installs a 92,000-line trojan framework with systemd persistence and HTTP/Nostr/Ethereum/libp2p C2 channels, targeting browser credentials, SSH keys, npm/GitHub tokens, AWS credentials, and crypto wallets. The piece also analyzes partial technical overlap with the Miasma malware framework and the unrelated prt-scan campaign without making definitive attribution.

TL;DR Attacker abused an unpatched GitHub Actions pull_request_target "pwn request" bug to steal a privileged PAT and push malicious @asyncapi npm packages carrying a novel "M-RED-TEAM" multi-channel C2 trojan.
Document

What it is

A July 14, 2026 supply-chain compromise of the AsyncAPI project. An attacker exploited a "pwn request" — a pull_request_target GitHub Actions workflow in asyncapi/generator that checked out the pull request's code instead of the base branch — to steal a privileged PAT belonging to the asyncapi-bot service account, then published trojaned npm packages under @asyncapi. The key operational detail the summary omits: the payload executes on import/require, not on install, so --ignore-scripts does not protect you.

How it works

pull_request_target runs in the base repo's context with full secret access. Because the vulnerable workflow checked out attacker-supplied PR code and executed it, secrets became reachable. The attacker's PR (#2155) contained a markdown file with obfuscated JavaScript hidden after ~1,000 bytes of whitespace; it scanned the runner environment for secrets and exfiltrated them to a rentry.co dead-drop. Automated review flagged the obfuscation and the PR was never merged — but the workflow had already run and the credentials were retrieved.

Timeline: PR opened 05:08 UTC, workflow completed 05:16 UTC, credentials retrieved. The attacker then pivoted to asyncapi/spec-json-schemas, pushed 11 commits (07:51–08:28 UTC), and published two more malicious @asyncapi/specs versions. In package payloads, the malicious code sits on the first line of legitimate source files, whitespace-padded off-screen.

Notable failure of process: a contributor filed a PoC for this exact issue on April 29 and a proposed fix on May 17 — splitting the workflow into two separate jobs to isolate secret access from untrusted code. That fix was still open, unmerged, 58 days later when the attack landed.

What to do

  • Audit CI/CD, developer workstations, and repos for the affected @asyncapi package versions.
  • Assume exposure and rotate GitHub tokens, SSH keys, cloud credentials, and CI/CD secrets.
  • Fix pull_request_target workflows: split jobs so secret-holding steps never execute untrusted PR code (do not checkout the PR head in a secret-bearing job).
  • Longer term: dependency allowlisting, SBOM generation, package verification.

IOCs / attribution signals

  • Rentry exfil slug elzotebo; config giteaPackagesOrg = miasma-test-org; persistence unit miasma-monitor.service; Nostr C2 uses miasma-branded tags; obfuscation via javascript-obfuscator with a custom base64 alphabet.
  • Stage 3 self-identifies as "M-RED-TEAM v6.4" in comments.

Caveats

Wiz makes no definitive attribution. Signals conflict: the code carries Miasma branding, but the rentry slug matches the prt-scan campaign — and prt-scan has not been linked to Miasma. Beyond the branding and initial obfuscation, the payload bears minimal resemblance to prior Miasma or Shai-Hulud code; it is a full Trojan command framework (Dirlist/GetFile/PutFile) rather than a worm. This is stated as not directly connected to the earlier Shai-Hulud 2.0 compromise of @asyncapi.

Organisations named here

  • AsyncAPI
  • asyncapi-bot

Technologies named here

  • Wiz
  • asyncapi/generator
  • javascript-obfuscator
  • @asyncapi npm packages
  • GitHub Actions
  • asyncapi/spec-json-schemas
  • IPFS
  • @asyncapi/specs
  • Nostr relays
  • Ethereum smart contracts
  • libp2p mesh network
  • systemd
  • rentry.co
  • npm
  • Ethereum
  • Nostr

Techniques named here

  • Pwn Request
  • Camouflage via noise
  • Obfuscated payload delivery
  • Secret exfiltration
  • Staged malware payload / persistence
  • Hidden malicious code padding
  • Credential and data theft

Threat actors named here

  • M-Red-Team
  • Miasma malware framework
  • Shai-Hulud 2.0
  • prt-scan campaign
  • Miasma
  • prt-scan