2026-07-14 · view entry permalink →
AsyncAPI npm packages backdoored via a GitHub Actions pull_request_target token theft, delivering a multi-stage IPFS implant (M-RED-TEAM)
On 2026-07-14 an attacker compromised the asyncapi/generator GitHub repository by abusing a pull_request_target workflow that checked out the pull request's own code while still running "in the context of the base repository with full access to secrets" (Wiz, 2026-07-14). The attacker opened 37 pull requests — almost all a decoy adding a fake charity-donation page — while a single one (PR #2155, 05:08 UTC) carried obfuscated JavaScript that scanned the Actions runner environment for secrets and exfiltrated them to a paste-site dead drop, capturing the token of asyncapi-bot, a service account with organization-wide access; by 06:58 UTC the attacker pushed a malicious commit to the next branch and from 07:10 UTC the release workflow published five trojanized versions across four packages — @asyncapi/generator 3.3.1, @asyncapi/generator-helpers 1.1.1, @asyncapi/generator-components 0.7.1, and @asyncapi/specs 6.11.2 and 6.11.2-alpha.1 — which "combined, these packages see over three million downloads a week" (Wiz, 2026-07-14). A contributor had opened a fix for the vulnerable workflow on 2026-05-17; it was still unmerged 58 days later when the attack landed.
The injected code executes on import/require, not at install time: it spawns a detached Node child process that downloads a later stage from IPFS into a per-user application-support directory, then runs an encrypted multi-stage bundle whose runtime "explicitly self-identifies as 'M-RED-TEAM v6.4' in code comments" (Wiz, 2026-07-14). It establishes persistence via a systemd user service on Linux (with platform-specific equivalents on macOS and Windows) and beacons over multiple command-and-control channels — HTTP, Nostr relays, Ethereum smart contracts, and a libp2p mesh — accepting remote commands for file operations, directory listing and data exfiltration; its obfuscation uses javascript-obfuscator with a custom base64 alphabet matching prior incidents. The bundle carries credential-theft capabilities targeting saved browser passwords and cookies, SSH keys, npm and GitHub tokens, AWS credentials, the macOS Keychain and crypto wallets. Wiz notes technical fingerprints overlapping the Miasma framework (a miasma-branded persistence service and relay tags) and a dead-drop naming pattern matching the separately-tracked prt-scan pull-request-abuse campaign, but states that "beyond the references and initial obfuscation method the payload contains minimal resemblance to previous Miasma and Shai-Hulud payloads" and that "at this time, we are not making any definitive attribution." SafeDep, tracking the same incident, reports the payload self-identifying as miasma-train-p1 rather than Wiz's M-RED-TEAM v6.4 and frames the Miasma link more directly — "this is either a private, parallel build by the same operators or a separate group that adopted the Miasma brand after the source was published" (SafeDep, 2026-07-14); a team hunting code-comment strings should check for both identifiers.
Defender takeaway. This is a recurring 2026 pattern of pull_request_target "pwn request" abuse feeding npm-ecosystem backdoors, and the load-bearing control gap is a CI/CD one: any workflow that triggers on pull_request_target and then checks out untrusted PR code runs attacker code with access to repository secrets. Audit your own Actions workflows for that pattern, and — because the payload runs on import rather than install — a --ignore-scripts install policy does not neutralise it; only pinning to known-good versions and rebuilding from a clean state does.
Triage: a legitimate require() of AsyncAPI tooling performs no runtime network activity; the signal is a detached Node child process spawned from an npm/node parent at import time that reaches out to an IPFS gateway or a peer-to-peer mesh and then creates a user-level persistence service — process-lineage telemetry (a script interpreter spawning a hidden detached child with outbound egress) plus a new systemd/user-service artifact created outside a package-manager transaction is the discriminator, since benign build tooling produces neither.
On July 14, 2026, an attacker opened 37 pull requests to the AsyncAPI generator repository. Almost all attempted to add a fake charity donation page.
The payload executes on import/require, not install.
The payload includes credential theft capabilities targeting browser saved passwords and cookies (Chrome, Brave, Firefox, Edge), SSH keys, npm and GitHub tokens, AWS credentials, macOS Keychain, and cryptocurrency wallets.
This is either a private, parallel build by the same operators or a separate group that adopted the Miasma brand after the source was published.
All five malicious versions were published through npm trusted publishing using GitHub OIDC and carried valid provenance attestations. The attestations accurately identified the legitimate repositories, commits, and workflows that created the packages, even though the triggering commits were unauthorized.
Do not rely on npm install –ignore-scripts as a mitigation; this campaign executes when the module is imported, not through a lifecycle hook.
Microsoft Threat Intelligence published a forensic timeline of the AsyncAPI npm compromise that adds a detail with broad supply-chain-defence implications (Microsoft Threat Intelligence, 2026-07-15). Once the attacker held push access as the AsyncAPI service account (via the pull_request_target misconfiguration covered in the original entry), no npm-token theft was needed: a direct push to a release-triggering branch ran the project's own legitimate release-with-changesets workflow, which published the packages via npm trusted publishing over GitHub OIDC. As a result the five trojanized versions carry cryptographically valid provenance attestations that correctly identify the real repository, commit and workflow — even though the triggering commit was unauthorized (Microsoft Threat Intelligence, 2026-07-15).
Two further deltas: the payload triggers at import time (embedded in one file per package — index.js for the specs package, validator.js/utils.js/ErrorHandling.js for the generator family) and unwraps an IPFS-fetched bundle through three static-key crypto layers to an eval(), so npm install --ignore-scripts provides no protection; and Microsoft recovered all three self-identifying strings — M-RED-TEAM v6.4, miasma-train-p1 and miasma-test-org — from one binary, resolving the identifier ambiguity across the original reporting. Unit 42 independently corroborates the timeline and identifies the payload as a descendant of the same Miasma RAT deployed in the June 2026 Red Hat supply-chain operation (Unit 42, 2026-07-15).