Skip to content

[SECURITY] Malicious versions published via compromised next branch - @asyncapi/generator@3.3.1, generator-helpers@1.1.1, generator-components@0.7.1 #2184

Description

@LidorMachluf

Summary

Three malicious versions of AsyncAPI packages were published to npm on 2026-07-14 at 07:10 UTC via a compromised CI workflow. A threat actor gained write access to the next branch and pushed a commit injecting a credential-stealing RAT dropper into the source of all three packages. All three versions are currently promoted as latest on npm.

The AsyncAPI project and its maintainers are victims of this attack - this is not an insider issue.


Affected Versions

Package Malicious Version Safe Version
@asyncapi/generator 3.3.1 3.3.0
@asyncapi/generator-helpers 1.1.1 1.1.0
@asyncapi/generator-components 0.7.1 0.7.0

What Happened

The compromised commit

Commit 3eab3ec9304aa26081358330491d3cfeb55cc245 was pushed to the next branch at 06:58:42 UTC with author identity "Your Name" / you@example.com - an unconfigured placeholder git identity, not any AsyncAPI contributor.

The commit modified three source files in the monorepo, injecting a ~7.7KB obfuscated JavaScript payload as a whitespace-padded single line (hidden ~1000 spaces off-screen) in each:

  • apps/generator/lib/templates/config/validator.js (line 69)
  • packages/helpers/src/utils.js
  • packages/components/src/utils/ErrorHandling.js

The release workflow on the next branch triggered automatically, and asyncapi-bot published all three packages via GitHub Actions OIDC within seconds.

Note: apps/react-sdk/src/utils/withNewLines.ts was also modified in the same commit with a different IPFS payload CID (Qmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyf). No matching npm package appears to have been published, but the @asyncapi/react-component scope should be audited.


Attack Chain

Stage 1 - fires at require() time (no install hook needed)

The injected IIFE runs immediately when the poisoned file is require()d during normal generator operation:

// Decoded from obfuscated blob in validator.js:69
spawn("node", ["-e", "<stage2_script>"], {
  detached: true,
  stdio: "ignore",
  windowsHide: true
}).unref()

No postinstall hook - the payload fires when the generator is used, not when it is installed.

Stage 2 - IPFS downloader (decoded from stage 1)

The inline script:

  1. Creates a hidden directory based on OS:
    • Linux: ~/.local/share/NodeJS/
    • macOS: ~/Library/Application Support/NodeJS/
    • Windows: %LOCALAPPDATA%\NodeJS\
  2. Downloads sync.js (8.25MB) from IPFS CID QmQobZSp1wRPrpSEQ56qnyq7ecZh5Bg5k1fnjt4SUwwHb9
  3. Executes it silently: spawn("node", ["<dir>/sync.js"], {detached: true, stdio: "ignore", windowsHide: true}).unref()
  4. Calls process.exit(0) - the parent exits cleanly, hiding any trace

Stage 3 - Miasma RAT (sync.js, fully decrypted)

sync.js is a self-decrypting AES-256-GCM payload (HKDF-SHA256, hardcoded master key rt-vault-master-key-32b-aaaaaaaa). Once decrypted it is a full credential-stealing RAT with:

Credential targets:

  • Browser profiles: Login Data, Cookies, Local State (Chrome, Brave, Firefox, Edge)
  • SSH keys: ~/.ssh/id_rsa, ~/.ssh/id_ed25519, ~/.ssh/config
  • npm token: ~/.npmrc
  • GitHub CLI: ~/.config/gh/
  • AWS: ~/.aws/credentials
  • Git config: ~/.gitconfig
  • macOS Keychain
  • Crypto wallets: MetaMask, Ledger

C2 infrastructure:

  • HTTP exfil: http://85.137.53.71:8081 (NL, AS43641 SOLLUTIUM EU) - confirmed live at time of discovery
  • Ethereum smart contract dead-drop: 0x12c37A86a0Ed0beBe5d1d6a43E42f07860eAc710 (mainnet)
  • Nostr relay C2: wss://relay.damus.io, wss://relay.nostr.com/

Campaign: Internal config identifies this as "miasma-train-p1" - part of the Miasma campaign active since June 2026, which previously targeted @vapi-ai/server-sdk, packages in the jagreehal GitHub org, and the @redhat-cloud-services scope.


Indicators of Compromise

Type Value
Malicious commit 3eab3ec9304aa26081358330491d3cfeb55cc245
IPFS CID (stage 2) QmQobZSp1wRPrpSEQ56qnyq7ecZh5Bg5k1fnjt4SUwwHb9
IPFS CID (react-sdk variant) Qmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyf
C2 / exfil IP 85.137.53.71 (NL, AS43641)
Ethereum contract 0x12c37A86a0Ed0beBe5d1d6a43E42f07860eAc710
Drop file (Linux) ~/.local/share/NodeJS/sync.js
Drop file (macOS) ~/Library/Application Support/NodeJS/sync.js
Drop file (Windows) %LOCALAPPDATA%\NodeJS\sync.js
Obfuscator fingerprint function _0x2d89, rotation constant 0x32b8b

Recommended Actions

For AsyncAPI maintainers (urgent)

  • Rotate all GitHub tokens and secrets - PATs, Actions secrets, deploy keys - the next branch write token is compromised
  • Audit branch protection on next - identify how the attacker gained push access; remove unknown keys
  • Force-push or delete the next branch to remove commit 3eab3ec9 (coordinate with GitHub Security if they want to preserve it for forensics)
  • Audit all @asyncapi scope packages for unauthorized versions published in the 07:05-07:15 UTC window today
  • Publish clean patch versions (3.3.2, 1.1.2, 0.7.2) once npm yanks the malicious ones, so users upgrading land on something safe
  • Publish a security advisory linking to this issue

For users who installed any affected version after 2026-07-14 07:10 UTC

  1. Check for the dropped file and delete if present:
    • Linux: ~/.local/share/NodeJS/sync.js
    • macOS: ~/Library/Application Support/NodeJS/sync.js
    • Windows: %LOCALAPPDATA%\NodeJS\sync.js
  2. Kill orphaned node processes originating from those directories
  3. Rotate credentials - treat all of the following as compromised: npm token, GitHub token, SSH private keys, AWS credentials
  4. Treat browser saved passwords as compromised - Chrome, Brave, Firefox, and Edge profile data was targeted
  5. Downgrade immediately to the safe versions listed above

Reported by Lidor Machluf / Upwind Security

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions