asyncapi / asyncapi/generator

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

Open
#2,184 28 comments 2 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
1.1k
Forks
397
Avg merge
1d 7h
Merged PRs (30d)
25

Description

## 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`](https://github.com/asyncapi/generator/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:

```javascript
// Decoded from obfuscated blob in validator.js:69
spawn("node", ["-e", ""], {
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", ["/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)

- [x] **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)
- [x] **Audit all `@asyncapi` scope packages** for unauthorized versions published in the 07:05-07:15 UTC window today
- [x] **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*

Contributor guide

Open the contributing guide

Research direction

Start by reviewing compromised commit 3eab3ec9 and the `next` branch GitHub Actions workflow, then inspect the three affected source files and the react SDK file named in the report. Done means identifying the branch-access failure, completing the remaining branch and security-advisory actions, and documenting the resulting containment and impact.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, javascript, node.js
Domain
ci-cd, release, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.