# AsyncAPI npm Supply Chain Attack: Pwn-Request GitHub Actions Compromise Deploys Miasma Tasking Framework

> An attacker exploited a 'pwn request' flaw in a misconfigured pull_request_target GitHub Actions workflow (manual-netlify-preview.yml) to steal a privileged asyncapi-bot Personal Access Token, then used the AsyncAPI project's own legitimate release pipelines and npm OIDC trusted-publisher integration to push five malicious @asyncapi package versions carrying valid SLSA provenance. The packages deployed a three-stage dropper culminating in a 744-module, 92,000-line Miasma-family tasking framework with six independent C2 channels (HTTP, Nostr, IPFS, BitTorrent DHT, libp2p GossipSub, Ethereum smart contract), credential/wallet theft, AI coding-assistant poisoning, LAN worm propagation, and a dead man's switch that wipes local directories if the stolen token is revoked.

- **Published:** 2026-07-15T00:00:00Z
- **Last reviewed:** 2026-10-29T08:47:34.039Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-1360
- **ID:** TL-2026-1360
- **Severity:** CRITICAL (CVSS 9.8)
- **Category:** SUPPLY_CHAIN
- **Status:** MITIGATED
- **Actor:** M-RED-TEAM
- **Detections:** 9 (1 shown free below) · **IOCs:** 54 (3 shown free below)

## Description

On 2026-04-29 a researcher reported a pull_request_target misconfiguration in asyncapi/generator's manual-netlify-preview.yml workflow; a proposed fix on 2026-05-17 was never merged. On 2026-07-14 an attacker weaponized the flaw: they opened 37 pull requests against asyncapi/generator, almost all a noisy decoy adding a fake charity donation page, while PR #2155 hid obfuscated JavaScript after roughly 1,000 bytes of whitespace. Because manual-netlify-preview.yml triggered on pull_request_target but checked out attacker-controlled PR code, the workflow executed with base-repository secrets and exfiltrated a highly privileged Personal Access Token belonging to the asyncapi-bot service account.

At 06:58 UTC the attacker pushed commit 3eab3ec9304aa26081358330491d3cfeb55cc245 to the next branch under the placeholder git identity "Your Name <you@example.com>" (GitHub API resolved the email as invalid, consistent with a compromised push credential rather than a legitimate contributor). This automatically triggered the project's own release-with-changesets.yml workflow via npm's GitHub OIDC trusted-publisher integration at 07:10 UTC, publishing @asyncapi/generator@3.3.1, @asyncapi/generator-helpers@1.1.1, and @asyncapi/generator-components@0.7.1 with valid SLSA provenance attestations -- attestations that prove only that the authorized workflow produced the artifact, not that the triggering commit was legitimate. Between 07:51-07:56 UTC the same attacker pushed commit 36269ce81837 to the master branch of asyncapi/spec-json-schemas, causing the if-nodejs-release.yml workflow to publish @asyncapi/specs@6.11.2-alpha.1 (08:06 UTC) and @asyncapi/specs@6.11.2 (08:30 UTC). Combined, the four packages see roughly 2-3 million weekly downloads.

Unlike prior npm supply-chain attacks that relied on postinstall lifecycle hooks (now restricted by npm v12), the dropper was injected directly into legitimate source files (apps/generator/lib/templates/config/validator.js, packages/helpers/src/utils.js, packages/components/src/utils/ErrorHandling.js, and the specs package's compiled ESM index.js) and fires the moment the module is require()'d during normal build or CI use -- not at npm install time. Stage 1 spawns a detached, stdio-suppressed Node.js child process (windowsHide:true) that downloads an encrypted Stage 2 blob from IPFS (CID QmQobZSp1wRPrpSEQ56qnyq7ecZh5Bg5k1fnjt4SUwwHb9 for the generator packages, Qmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyf for specs) and drops it to an OS-specific hidden path (sync.js under NodeJS support directories on Windows/macOS/Linux). Stage 2 decrypts an 8.25MB bundle using AES-256-GCM with HKDF-SHA256 key derivation (labels rt-vault-master-key-32b-aaaaaaaa, rt-file-key-material-v1, rt-baked-key) to yield Stage 3: a 3.08-3.09MB, ~92,000-line JavaScript tasking framework that self-identifies in code as both "miasma-train-p1" and "M-RED-TEAM v6.4".

The framework implements 744 bundled modules and 12+ command handlers (file listing/retrieval/write, shell execution, payload update, beacon-interval update, credential ciphering, node signing) across six independent C2 channels: primary HTTP/REST beaconing to 85.137.53.71:8080 (/api/v1/beacon, /api/v1/file-result) with dedicated upload (8081) and proxy-management (8091) ports, Nostr relay fallback (wss://relay.damus.io, wss://relay.nostr.com), IPFS, BitTorrent DHT (router.bittorrent.com, router.utorrent.com, dht.transmissionbt.com), libp2p GossipSub P2P mesh, and an Ethereum smart contract (0x12c37A86a0Ed0beBe5d1d6a43E42f07860eAc710) as a blockchain dead-drop fallback. Credential-theft targets npm/GitHub/PyPI tokens, SSH keys, browser-stored passwords, macOS Keychain, and AWS/Azure/GCP cloud credentials. A dedicated ai-tool-poisoner.js module targets Claude Code, GitHub Copilot, and Cursor configuration, meaning any AI coding session on an affected workstation must be treated as compromised. LAN lateral movement uses subnet scanning and mDNS discovery; a metamorphic mutation engine supports polymorphic re-propagation, though baked configuration toggles for PyPI/RubyGems/Cargo/cryptocurrency propagation modules were observed disabled despite the code being present. Persistence is established via a systemd user service (~/.config/systemd/user/miasma-monitor.service, Restart=always), crontab, macOS launchd, and Windows Registry Run keys. Anti-analysis logic terminates on detected sandboxes/VMs, on hosts with a Russian system locale, or where CrowdStrike, SentinelOne, Microsoft Defender, CarbonBlack, Cylance, Osquery, Tanium, or Qualys are present. A dead man's switch continuously monitors validity of the stolen token and triggers a local directory wipe if it is revoked.

All five malicious versions were unpublished from npm between 11:12-11:18 UTC on 2026-07-14 (exposure windows of roughly 2h48m-4h3m); the latest dist-tags now resolve to clean versions (generator@3.3.0, generator-helpers@1.1.0, generator-components@1.0.0, specs@6.11.1). Researchers note code-level obfuscation overlaps and shared naming conventions with the prior Red Hat Cloud Services npm 'Miasma: The Spreading Blight' campaign (itself built on leaked/open-sourced Shai-Hulud code) and the 'prt-scan' Rentry dead-drop campaign, but caution that no definitive attribution has been established -- one analysis argues the 'Miasma' strings may be a deliberate false-flag to mislead responders. Regardless of branding, defenders should treat any endpoint or CI runner that imported or executed one of the five affected package versions as compromised: rotate npm/GitHub/SSH/cloud credentials, remove dropper artifacts and orphaned processes, audit CI egress logs for connections to ipfs.io, 85.137.53.71, DHT bootstrap nodes, or Nostr relays, and treat AI coding-assistant sessions on affected hosts as untrusted.

## MITRE ATT&CK

- T1583.004 Server
- T1588.001 Malware
- T1195.002 Compromise Software Supply Chain
- T1199 Trusted Relationship
- T1059.007 JavaScript
- T1204.002 Malicious File
- T1543.002 Systemd Service
- T1053.003 Cron
- T1543.001 Launch Agent
- T1547.001 Registry Run Keys / Startup Folder
- T1027 Obfuscated Files or Information
- T1140 Deobfuscate/Decode Files or Information
- T1497.001 System Checks
- T1036.005 Match Legitimate Resource Name or Location
- T1685 Disable or Modify Tools
- T1555.003 Credentials from Web Browsers
- T1555.001 Keychain
- T1552.001 Credentials In Files
- T1552.005 Cloud Instance Metadata API
- T1528 Steal Application Access Token
- T1082 System Information Discovery
- T1518.001 Security Software Discovery
- T1046 Network Service Discovery
- T1016 System Network Configuration Discovery
- T1570 Lateral Tool Transfer
- T1005 Data from Local System
- T1560 Archive Collected Data
- T1071.001 Web Protocols
- T1571 Non-Standard Port
- T1102.002 Bidirectional Communication
- T1095 Non-Application Layer Protocol
- T1090 Proxy
- T1041 Exfiltration Over C2 Channel
- T1485 Data Destruction
- T1195.001 Supply Chain Compromise
- T1059.004 Command and Scripting Interpreter
- T1546.004 Event Triggered Execution
- T1027.002 Obfuscated Files or Information
- T1564.001 Hidden Files and Directories
- T1105 Ingress Tool Transfer

## Free detection (Splunk SPL, Microsoft KQL, Sigma)

**Node.js Spawns Hidden PowerShell Child Process (Miasma require()-Trigger)** (`TL-2026-1360-SPL-001`)

Detects the exploitation trigger for the Miasma dropper: a hidden, stdio-suppressed PowerShell process spawned by node.exe the moment a poisoned @asyncapi module is require()'d during build/CI, not at npm install time.

- **Languages:** Splunk SPL, Microsoft KQL, Sigma
- **ATT&CK:** T1059.007, T1204.002, T1027
- **Data sources:** sysmon, windows_security, microsoft_defender_for_endpoint
- **Severity:** critical
- **Confidence:** high

### Splunk SPL

```spl
index=endpoint sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
| where match(ParentImage, "(?i)\\\\node\.exe$") AND match(Image, "(?i)\\\\powershell\.exe$")
| where match(CommandLine, "(?i)-windowstyle\s+hidden") AND match(CommandLine, "(?i)-noprofile")
| eval risk_reason="node.exe spawned hidden PowerShell child during require()"
| table _time, ComputerName, User, ParentImage, Image, CommandLine, ProcessGuid, risk_reason
| sort -_time
```

### Microsoft KQL

```kql
DeviceProcessEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName =~ "node.exe"
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has "-WindowStyle" and ProcessCommandLine has "Hidden"
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine, InitiatingProcessId, ProcessId
```

### Sigma

```yaml
title: Suspicious Hidden PowerShell Child Process Spawned by Node.js (Miasma Dropper Trigger)
id: 7c2a1e10-4b3d-4a2f-9e5c-1a2b3c4d5e01
status: experimental
description: Detects a hidden, stdio-suppressed PowerShell process spawned by node.exe, matching the Miasma/AsyncAPI supply-chain dropper's require()-time Stage 1 trigger
references:
    - https://socket.dev/blog/asyncapi-supply-chain-attack
    - https://www.wiz.io/blog/m-red-team-asyncapi-supply-chain-compromise-via-github-actions
author: AII-Detector — ThreadLinqs Intelligence
date: 2026-07-15
tags:
    - attack.execution
    - attack.t1059.007
    - attack.t1204.002
    - attack.tool.miasma
logsource:
    product: windows
    category: process_creation
detection:
    selection:
        ParentImage|endswith: '\node.exe'
        Image|endswith: '\powershell.exe'
        CommandLine|contains|all:
            - '-WindowStyle'
            - 'Hidden'
    condition: selection
falsepositives:
    - Legitimate Node.js build tooling that shells out to PowerShell for signing/packaging scripts
level: high
```

**Known false positives:**

- Legitimate CI/build scripts that intentionally launch hidden PowerShell helpers from Node.js tooling

**Tuning notes:** Scope to CI runner and developer-workstation asset groups first to reduce noise from unrelated automation; add an allowlist for known internal build scripts once validated.

### 8 more detection rules (Splunk SPL, Microsoft KQL, Sigma), unlock with TL Creds

- Registry Run Key Persistence Under Generic Monitor/Sync Name (Miasma-style) (locked: unlock with TL Creds)
- systemd User Service Created with Restart=always by Non-Package-Manager Process (locked: unlock with TL Creds)
- Anti-Analysis Security-Tool Enumeration Preceding Credential-Store Access (locked: unlock with TL Creds)
- Placeholder-Identity Commit Directly Preceding OIDC-Triggered npm Publish (locked: unlock with TL Creds)
- Multi-Channel Beacon Pattern: HTTP + Nostr/IPFS/DHT Fallback with Jitter (locked: unlock with TL Creds)
- LAN Subnet Scan / mDNS Discovery Originating from Node.js Process (locked: unlock with TL Creds)
- Poisoned npm Package require() Triggers Outbound IPFS Fetch (locked: unlock with TL Creds)
- Malicious @asyncapi Package Version Resolved in Build/Install (locked: unlock with TL Creds)

Sign up free to unlock the detection rules: https://threadlinqs.com/?modal=signup

## Sample indicators (3 of 54)

Defanged, TLP:CLEAR.

- IP address: `85.137.53[.]71`
- Domain: `router[.]bittorrent[.]com`
- File hash: `34014776d3d3ff11bc4439b02fd7ac0f02a887eb3a052eeafff236e2f6db8ad1`

Full set of 54 indicators unlocks with TL Creds: https://threadlinqs.com/tl-creds

## Sources

- [Compromised AsyncAPI npm Packages Deliver Miasma Tasking Framework via CI/CD Pipeline Hijack](https://thehackernews.com/2026/07/compromised-asyncapi-npm-packages.html)
- [Compromised npm Packages in the AsyncAPI Namespace Deliver Miasma](https://socket.dev/blog/asyncapi-supply-chain-attack)
- [Coordinated AsyncAPI Supply Chain Attack: Miasma RAT Delivered via Compromised CI/CD Pipelines in Two Repositories](https://www.stepsecurity.io/blog/compromised-next-branch-pushes-malicious-asyncapi-generator-generator-helpers-and-generator-components-to-npm)
- [AsyncAPI npm organization compromised, 2M weekly downloads affected](https://www.ox.security/blog/asyncapi-npm-organization-compromised-2m-weekly-downloads-affected/)
- [M-Red-Team: AsyncAPI Supply Chain Compromise via GitHub Actions](https://www.wiz.io/blog/m-red-team-asyncapi-supply-chain-compromise-via-github-actions)
- [AsyncAPI Packages Compromised with Miasma RAT](https://safedep.io/asyncapi-generator-supply-chain-attack-miasma-rat/)
- [AsyncAPI npm packages backdoored via GitHub Actions](https://www.aikido.dev/blog/asyncapi-npm-packages-backdoored-via-github-actions)
- [Miasma Supply Chain Attack Compromises Red Hat npm Packages with Credential-Stealing Worm](https://thehackernews.com/2026/06/miasma-supply-chain-attack-compromises.html)

## Full data

The other 8 detection rules (Splunk SPL / Microsoft KQL / Sigma) unlock with TL Creds; a free account includes daily creds: https://threadlinqs.com/?modal=signup
Indicator values unlock with TL Creds, at a lower price on Red and Purple; AI agents can query rules and IOCs through the Threadlinqs MCP server (Purple): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-1360
