Miasma Worm 73: Inside the Microsoft/GitHub Supply Chain Attack Targeting 73 Tech Organisations

·

On June 5–6, 2026, GitHub disabled 73 repositories across Microsoft's Azure, Azure-Samples, Microsoft, and MicrosoftDocs GitHub organizations after a self-replicating supply chain worm — designated Miasma — propagated through the npm ecosystem using a novel exploitation of Node's native build system. The worm is an evolution of the Mini Shai-Hulud campaign released by the threat group TeamPCP in mid-May 2026.

Miasma's distinguishing feature is its abuse of binding.gyp — a native addon configuration file — to execute a 4.29 MB credential-harvesting payload during npm install without touching package.json scripts, bypassing virtually every security scanner that monitors lifecycle hooks. Once detonated, the Bun-based worm harvests cloud credentials across AWS, Azure, GCP, GitHub, npm, and Kubernetes, then autonomously commits itself into every repository the stolen tokens can write to.

This post presents a full DFIR walkthrough: how the worm works, how it spread to Microsoft's repos, what it stole, where it sent the data, and exactly what defenders need to hunt for right now.

◈ Table of Contents

01 Campaign Timeline 02 The binding.gyp Zero-Click Exploit 03 4-Stage Obfuscation Pipeline 04 Credential Harvesting Arsenal 05 Worm Propagation & C2 Infrastructure 06 DFIR Investigation Steps 07 Indicators of Compromise 08 Detection & Hunt Queries 09 MITRE ATT&CK Mapping 10 Sources
🕐

Phase 1 — Campaign Timeline

CONTEXT
01
Miasma's Origins and Escalation Path
Timeline

Miasma did not emerge in a vacuum. It traces directly to TeamPCP's publicly released Mini Shai-Hulud worm prototype from mid-May 2026. What started as a proof-of-concept evolved into a fully operational threat actor tool over three weeks, absorbing lessons from a previous run against 32 Red Hat npm packages.

Escalation Timeline
  • 1Mid-May 2026: TeamPCP publicly releases Mini Shai-Hulud worm prototype. Core innovation: using binding.gyp to trigger execution during npm install without touching package.json scripts.
  • 2Late May 2026: Miasma variant mutates, targeting 32 @redhat-cloud-services npm packages across 90+ versions. Campaign compromises TanStack, Mistral AI, and UiPath npm packages. Total infected packages reach 57, spanning 286+ versions.
  • 3June 1–4, 2026: Microsoft Security Blog documents the Red Hat npm campaign in detail. GitHub begins notifying affected maintainers. Worm propagation continues into new ecosystems including PyPI and RubyGems.
  • 4June 5, 2026 (07:30 UTC est.): Miasma reaches Microsoft's Azure/durabletask repository via a previously compromised contributor account. Malicious commit plants .claude/setup.mjs and .cursor/rules/setup.mdc backdoor files alongside a 4.3 MB payload runner.
  • 5June 5, 2026 (07:31:45 UTC est.): GitHub's automated systems trigger. Within a 105-second window, 73 repositories across Azure, Azure-Samples, Microsoft, and MicrosoftDocs organizations are disabled. GitHub notifies Microsoft security teams.
  • 6June 6, 2026: StepSecurity, The Hacker News, and thenextweb report the incident publicly. GitHub confirms the campaign marker "Miasma: The Spreading Blight" embedded in payload and repo descriptions. C2 account github.com/liuende501 with 236 credential dead-drop repositories identified.
Miasma campaign spread by victim organization
MIASMA CAMPAIGN — COMPROMISED PACKAGES AND REPOSITORIES BY VICTIM ORGANIZATION
⚙️

Phase 2 — The binding.gyp Zero-Click Exploit

INITIAL EXECUTION
01
Why binding.gyp — Bypassing Lifecycle Hook Scanners
TTP

Every npm security scanner worth its salt monitors preinstall, postinstall, and install scripts inside package.json. Miasma bypasses all of them by abusing binding.gyp — a file used by Node's native addon build system (node-gyp) to compile C/C++ extensions. When node-gyp processes this file, it evaluates embedded shell commands through GYP's command substitution syntax.

The 157-Byte Payload Trigger
  • 1Miasma plants a binding.gyp file with a single malicious entry in the sources array using GYP command substitution: "<!(node index.js > /dev/null 2>&1 && echo stub.c)"
  • 2When a developer runs npm install, node-gyp processes binding.gyp to build the native addon. It evaluates the <!() expression, executing node index.js — the malicious payload — as a side effect of "compiling."
  • 3The malicious index.js is placed at the package root (not dist/index.js), weighing in at 4+ MB — a clear anomaly detectable by build artifact scanning.
  • 4Stderr is redirected to /dev/null and execution is chained with && echo stub.c to return a valid stub source file name, making the build appear normal to node-gyp.
The 157-byte binding.gyp exploit
# Miasma binding.gyp — 157 bytes — bypasses all package.json lifecycle hook scanners { "targets": [{ "target_name": "stub", "sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"] }] }

npm install --ignore-scripts does NOT protect against this. The binding.gyp trigger fires via node-gyp during native addon compilation, which is a separate code path from npm lifecycle scripts. Standard --ignore-scripts flags are ineffective.

MIASMA ATTACK CHAIN — npm install TO FULL WORM PROPAGATION
🔒

Phase 3 — 4-Stage Obfuscation Pipeline

EVASION
01
Multi-Layer Obfuscation to Defeat Static Analysis
Evasion

Miasma's payload is protected by four nested obfuscation layers, each designed to defeat a different class of static analysis. The final decrypted payload runs inside a Bun JavaScript runtime — not Node.js — specifically to evade Node-focused security monitoring tools deployed in most CI/CD pipelines.

The 4 Obfuscation Stages
  • 1Stage 0 — Preinstall Bootstrap: A 4.29 MB dropper is embedded in the malicious package. The binding.gyp trigger executes node index.js, which loads this dropper without any user-visible output.
  • 2Stage 1 — ROT-N Caesar Cipher: Character-code arrays are decoded with variable rotation values (ROT-9 through ROT-20 observed across versions). Dynamically executed via eval(). Purpose: defeats simple string-matching signatures.
  • 3Stage 2 — AES-128-GCM Encryption: Two encrypted blobs with embedded keys, IVs, and auth tags. After decryption, the payload downloads the Bun v1.3.13 JavaScript runtime from official Bun GitHub releases, then executes the main payload via Bun to bypass Node.js-focused monitoring.
  • 4Stage 3–4 — Obfuscator.io + PBKDF2: A 668 KB main malware module with a 2,306-entry encrypted string table. Protected with custom PBKDF2-HMAC-SHA-256 (200,000 iterations) to make decryption computationally expensive for sandboxes. Process execution chain: node → shell → bun → payload.

The Bun runtime download is the most reliably detectable stage. Bun is rarely present in CI/CD environments and its download from github.com/oven-sh/bun/releases during an npm install is highly anomalous. Monitor for curl/wget to that URL pattern from build tooling processes.

🔑

Phase 4 — Credential Harvesting Arsenal

IMPACT
01
What Miasma Steals — Complete Credential Inventory
Data Theft

Miasma's credential harvester is comprehensive. It targets every cloud platform and developer tool a typical CI/CD runner might have access to. Particularly notable is the GitHub Actions runner process memory scraping technique, which extracts masked secrets that would otherwise never appear in logs.

Target PlatformHarvesting MethodData Stolen
GitHubToken validation, GraphQL branch history extraction, Runner.Worker process memory scan via /procOAuth tokens, ACTIONS_RUNTIME_TOKEN, ACTIONS_ID_TOKEN_REQUEST_TOKEN, org secrets, Actions secrets
npm Registry/-/whoami validation, OIDC token exchange for elevated publish rightsnpm auth tokens, OIDC publish tokens, maintainer package lists
AWSIMDS v2 endpoint (169.254.169.254), ECS task metadata endpoint (169.254.170.2)IAM access keys, session tokens, Secrets Manager content
AzureIMDS OAuth2 at management.azure.com, graph.microsoft.com, *.vault.azure.netManaged identity tokens, Key Vault secrets, Azure credentials
GCPmetadata.google.internal service-account tokens, Secret Manager, Resource ManagerService account private keys, OAuth scopes, GCP project secrets
HashiCorp VaultProbed at 127.0.0.1:8200 across multiple token pathsVault tokens, KV secrets
KubernetesService Account token at /var/run/secrets/kubernetes.io/serviceaccount/tokenK8s service account tokens, namespace secrets
CI/CDEnvironment variable scrapingCircleCI tokens, SSH private keys, CLI credentials
Local StoresFile system traversal1Password, gopass, pass credential managers, browser/wallet data
GitHub Actions runner memory scraping command
# Miasma extracts masked GitHub Actions secrets from Runner.Worker process memory # Finds process via /proc scanning, then strips null bytes and greps for secret patterns cat /proc/[Runner.Worker PID]/mem | tr -d '\0' | grep -aoE \ '"[^"]+":{"value":"[^"]*","isSecret":true}'

This memory scraping technique defeats GitHub's secret masking entirely. Secrets marked isSecret:true in the runner runtime are still present in process memory and extractable via /proc. There is no reliable mitigation short of running builds in fully isolated, ephemeral VMs with no /proc access.

📡

Phase 5 — Worm Propagation & C2 Infrastructure

PROPAGATION
01
Three-Channel Exfiltration and Worm Spread
C2

Miasma uses three distinct exfiltration channels simultaneously. Channel A drops stolen credentials to GitHub dead-drop repositories. Channel B injects worm source code into accessible repositories for propagation. Channel C — currently dormant — uses api.anthropic.com as a swappable live exfiltration endpoint.

Channel A — Credential Dead-Drop
  • 1Creates a new public repository in the compromised developer's GitHub account. Repository description contains campaign marker: "Miasma: The Spreading Blight".
  • 2Commits stolen credentials as RSA-encrypted JSON to results/results-{timestamp}.json. Repository names follow pattern {adjective}-{creature}-{0–99999} (e.g., nemean-hydra-34343).
  • 3Primary C2 collection account: github.com/liuende501 with 236 programmatically-created credential storage repositories. Stolen tokens double-Base64 encoded in transit. Traffic spoofs python-requests/2.31.0 User-Agent.
  • 4C2 rotates across a pool of 16 attacker-controlled GitHub accounts per session. This distributes the data collection and complicates takedown efforts.
Channel B — Worm Propagation via Git Data API
  • 1Enumerates all accessible repositories via /user/repos and /user/orgs using stolen GitHub tokens.
  • 2Injects worm source code as .github/setup.js, .claude/setup.mjs, and .cursor/rules/setup.mdc into non-protected repository branches via the Git Data API (blob → tree → commit → ref update).
  • 3Skips protected branches, default branches named main/master where protection is detected, and bot-owned repositories. Spoofs commit identity using [email protected] to blend with automated CI commits.
  • 4Forges SLSA provenance attestations through Sigstore (Fulcio/Rekor) and republishes poisoned npm packages using stolen npm OIDC tokens with fraudulent provenance metadata.

The honeytoken behavior is destructive: Miasma embeds a token labelled "IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner." Revoking this token triggers a wiper payload executing "rm -rf ~/" and "~/Documents" on the victim machine. Do NOT blindly revoke tokens without first checking the Miasma IOC list.

🔍

Phase 6 — DFIR Investigation Steps

INVESTIGATION
01
Triage: Determine If You Were Hit
Triage
Immediate Triage Checklist
  • 1Audit npm packages installed in the last 30 days against the compromised package list. Check for any @redhat-cloud-services/*, @vapi-ai/server-sdk, ai-sdk-ollama, or autotel family packages in your lockfiles.
  • 2Search all repositories for Miasma backdoor files: .claude/setup.mjs, .cursor/rules/setup.mdc, .github/setup.js. These files were planted by the worm propagation module in any repo accessible to stolen tokens.
  • 3Check for anomalous binding.gyp files: Any binding.gyp containing <!(node or node index.js in the sources array is malicious. Legitimate native addons reference C/C++ source files, not JavaScript.
  • 4Audit GitHub public repositories created by any organizational members in the last 60 days. Look for repos with descriptions matching "Miasma: The Spreading Blight" or with results/ directories containing JSON files.
  • 5Review Bun runtime downloads in build system logs. Any curl or wget fetching from github.com/oven-sh/bun/releases during an npm install operation indicates compromise.
02
Containment: Credential Rotation Sequence
Containment

If compromise is confirmed, credential rotation must follow a specific sequence to avoid triggering the destructive honeytoken wiper. Rotate in this order to minimize blast radius.

Safe Credential Rotation Order
  • 1FIRST — Identify honeytoken: Before revoking ANY GitHub tokens, check each token against the IOC list. The token IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner is a named honeytoken that triggers destructive wiper on revocation. Isolate machines that may execute it before touching tokens.
  • 2Cloud credentials (AWS/Azure/GCP) first: These are the highest-value targets and have no honeytoken risk. Rotate all IAM keys, managed identity tokens, and service account credentials immediately. Invalidate all active sessions.
  • 3GitHub tokens: After confirming no honeytoken exposure, revoke compromised GitHub tokens via Settings → Developer settings → Personal access tokens. Audit OAuth app authorizations.
  • 4npm tokens: Revoke all npm publish tokens. Audit any packages published in the past 30 days for version tampering. Compare against official checksums.
  • 5CI/CD secrets: Rotate all GitHub Actions secrets, CircleCI environment variables, and SSH deploy keys. Re-evaluate secret scope — CI secrets should never have write access to production.
03
Forensic Collection Priorities
Forensics
Evidence Preservation
  • 1Preserve build logs from all CI/CD systems for the relevant time window. Look for the node → shell → bun execution chain. GitHub Actions: navigate to the workflow run and export full logs before they expire (default 90 days).
  • 2Capture network logs from build agents. Key outbound destinations: api.github.com, github.com/oven-sh, 169.254.169.254 (IMDS), 169.254.170.2 (Azure IMDS), metadata.google.internal.
  • 3Snapshot the compromised package versions from npm cache before clearing. The malicious index.js files (SHA-256 hashes in Phase 7) are valuable for malware analysis and legal holds.
  • 4Audit git history of all repositories for commits from [email protected] that introduced .claude/, .cursor/, or .github/setup.js files. These commits should not exist in repos without GitHub Actions workflows that produce them.
  • 5Check liuende501 GitHub account for repositories containing your organization's secrets. If found, this is evidence of exfiltration. Do not delete — preserve as evidence and report to GitHub Trust & Safety.
Key Forensic Findings to Document
  • Time of first binding.gyp execution in build logs
  • Bun runtime download timestamp and source URL
  • List of repos containing injected backdoor files
  • Cloud IMDS access patterns from build agent network logs
  • npm packages published during the compromise window
  • GitHub API calls to /user/repos and /user/orgs from build agents
📋

Phase 7 — Indicators of Compromise

IOCs
01
File Hashes — Malicious index.js Variants
Hashes
SHA-256 HashFileNotes
396cac9e457ec54ff6d3f6311cb5cc1da8054d019ce3ffa1de5741506c7a4ea4index.js (v1)@redhat-cloud-services/types
d8d170af3de17bb9b217c52aaaffdf9395f35ef015a57ef676e406c121e5e223index.js (v2)@redhat-cloud-services/frontend-components
f0641e053e81f0d01fa46db35a83e0a34494886503086866d956d14e81fd3e1cindex.js (v3)@redhat-cloud-services/rbac-client
d5a97614d5319ce9c8e01fa0b4eb06fb5b9e54fa13b23d718174a1546444123bindex.js (v4)@vapi-ai/server-sdk variant
f88258e21592084a2f93a572ade8f9b91c0cd0e242f5cf6121ed7bad0f7bdd1findex.js (v5)ai-sdk-ollama variant
25e121e3b7d300c0d0075b33e5eca39a3e6a659fb9cfee52b70ef71686628f1bindex.js (v6)autotel family variant
02
Network, File System & Behavioral IOCs
Indicators
TypeIndicatorSignificance
GitHub Accountgithub.com/liuende501Primary C2 credential dead-drop — 236 repos
File Path.claude/setup.mjsWorm backdoor injected into repos via Git API
File Path.cursor/rules/setup.mdcWorm backdoor targeting Cursor IDE users
File Path.github/setup.jsWorm propagation file in GitHub repos
File Contentbinding.gyp containing <!(node index.jsExploit trigger — 100% malicious
File Sizeindex.js > 4MB at package root (not dist/)Payload dropper — legitimate packages never have this
Networkgithub.com/oven-sh/bun/releases/* download during npm installStage 2 Bun runtime download — highly anomalous in CI
Network169.254.169.254 from npm install processAWS IMDS credential theft
Network169.254.170.2 from npm install processAzure IMDS credential theft
Networkmetadata.google.internal from npm install processGCP metadata credential theft
Process Chainnode → sh → bun → [payload]Miasma execution chain — no legitimate use case
Campaign MarkerRepo description: "Miasma: The Spreading Blight"Attacker marker in credential dead-drop repos
Search Keywordthebeautifulmarchoftime in GitHub searchCampaign beacon keyword used by worm to find infected repos
npm ScopeEntire @redhat-cloud-services namespaceAll packages in this scope across versions 2026-05-xx
Quick triage — scan for Miasma backdoor files across all repos
# Check current repo for Miasma backdoor files $ find . -name "setup.mjs" -path "*/.claude/*" -o \ -name "setup.mdc" -path "*/.cursor/*" -o \ -name "setup.js" -path "*/.github/*" 2>/dev/null # Check for malicious binding.gyp $ grep -r '<!(node' --include="binding.gyp" . # Check for oversized root index.js (legitimate = small; Miasma = 4+ MB) $ find . -maxdepth 2 -name "index.js" -size +3M -not -path "*/node_modules/*" # Scan npm lockfile for compromised package versions $ grep -E "@redhat-cloud-services|vapi-ai/server-sdk|ai-sdk-ollama" package-lock.json
🎯

Phase 8 — Detection & Hunt Queries

DETECTION
01
Microsoft Defender for Endpoint — KQL Hunt Queries
KQL
KQL — Bun Runtime Download During npm Install
// Detect Bun runtime download from npm install process chain DeviceNetworkEvents | where RemoteUrl has "github.com/oven-sh/bun/releases" or RemoteUrl has "bun.sh" | where InitiatingProcessFileName in~ ("node.exe", "node", "npm", "npm.cmd") or InitiatingProcessParentFileName in~ ("node.exe", "node") | project Timestamp, DeviceName, RemoteUrl, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessParentFileName | order by Timestamp desc
KQL — Anomalous node → bun Process Chain
// Detect Miasma's node-gyp → bun execution chain DeviceProcessEvents | where FileName in~ ("bun", "bun.exe") and (FolderPath has_any ("/tmp/", "AppData\\Local\\Temp", "/var/tmp/")) | where InitiatingProcessParentFileName in~ ("node", "node.exe", "sh", "bash", "cmd.exe") | project Timestamp, DeviceName, FileName, FolderPath, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessParentFileName | order by Timestamp desc
KQL — Cloud IMDS Access from Build Tool Processes
// Detect npm/node accessing cloud metadata endpoints (credential theft) DeviceNetworkEvents | where RemoteIP in ("169.254.169.254", "169.254.170.2") or RemoteUrl has "metadata.google.internal" | where InitiatingProcessFileName in~ ("node", "node.exe", "bun", "npm", "npm.cmd", "sh", "bash") | project Timestamp, DeviceName, RemoteIP, RemoteUrl, InitiatingProcessFileName, InitiatingProcessCommandLine | order by Timestamp desc
KQL — GitHub Actions Runner Memory Access Pattern
// Detect process reading /proc/[PID]/mem (Runner.Worker scraping) DeviceProcessEvents | where ProcessCommandLine has "/proc/" and ProcessCommandLine has "/mem" and ProcessCommandLine has_any ("tr -d", "grep -aoE", "isSecret") | project Timestamp, DeviceName, ProcessCommandLine, InitiatingProcessFileName, AccountName | order by Timestamp desc
02
Sigma Rule — Miasma binding.gyp Trigger
Sigma
Sigma Detection Rule
title: Miasma Supply Chain Worm — binding.gyp Code Execution id: a7f3e291-5b2c-4d80-9e6f-1a8c3b7d4e25 status: stable description: Detects Miasma worm execution via binding.gyp node-gyp command substitution references: - https://www.stepsecurity.io/blog/binding-gyp-npm-supply-chain-attack-spreads-like-worm logsource: category: process_creation detection: selection: ParentImage|endswith: - '/node-gyp' - '\node-gyp.cmd' Image|endswith: - '/node' - '\node.exe' CommandLine|contains: 'index.js' bun_download: CommandLine|contains: - 'oven-sh/bun' - 'bun/releases' condition: selection or bun_download falsepositives: - Legitimate native addons using node index.js in sources (very rare; review manually) level: high tags: - attack.execution - attack.t1195.001 - attack.t1059.007
🎯

Phase 9 — MITRE ATT&CK Mapping

ATT&CK
Technique IDTechnique NameMiasma Implementation
T1195.001Supply Chain Compromise: Compromise Software DependenciesPoisoned @redhat-cloud-services and 56 other npm packages
T1059.007Command and Scripting Interpreter: JavaScript4-stage JavaScript obfuscation pipeline, Bun runtime execution
T1027Obfuscated Files or InformationROT-N + AES-128-GCM + Obfuscator.io + PBKDF2 (200k iterations)
T1555Credentials from Password Stores1Password, gopass, pass credential manager theft
T1552.004Unsecured Credentials: Private KeysSSH key theft from CI/CD environments
T1528Steal Application Access TokenGitHub OAuth tokens, npm OIDC tokens, CI/CD secrets
T1087Account DiscoveryGitHub /user/repos and /user/orgs enumeration
T1041Exfiltration Over C2 ChannelRSA-encrypted JSON to liuende501 GitHub dead-drops
T1543.002Create or Modify System Processsudoers injection: runner ALL=(ALL) NOPASSWD:ALL
T1036MasqueradingSpoofed [email protected] commits, python-requests User-Agent
T1553.006Subvert Trust Controls: Code Signing PolicyForged SLSA provenance via Sigstore/Fulcio/Rekor
T1485Data DestructionHoneytoken wiper: rm -rf ~/ and ~/Documents on token revocation
📰

Phase 10 — Sources & References

SOURCES
Microsoft Security Blog — Preinstall to persistence: Inside the Red Hat npm Miasma credential-stealing campaign StepSecurity — Miasma npm Supply Chain Attack: Self-Spreading Worm via Phantom Gyp The Hacker News — Miasma Worm Hits 73 Microsoft GitHub Repositories in Major Supply Chain Attack The Next Web — Self-replicating Miasma worm hits 73 Microsoft GitHub repositories in supply chain attack The Hacker News — IronWorm and New Miasma Worm Variant Hit npm in Supply Chain Attacks

Hunt Miasma IOCs in your environment right now

Use the CyberHawk IOC Scanner to check your environment against all Miasma file hashes and network indicators. Full threat intel and detection packs available at cyberhawkthreatintel.com/threats.

◈ Stay Connected

Follow CyberHawk Threat Intel for threat intelligence, deployment guides and hands-on SOC tooling content.

🌐 Website ▶️ YouTube ▶️ YouTube (2) 𝕏 Twitter / X ♪ TikTok ✈️ Telegram
🔍 IOC Scanner 🛠️ Live Tools 📚 Courses 🚨 Threat Intel 📝 Blog 📋 SOPs

"They can't exploit you if you are the Exploit."