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
Phase 1 — Campaign Timeline
CONTEXTMiasma 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.
- 1Mid-May 2026: TeamPCP publicly releases Mini Shai-Hulud worm prototype. Core innovation: using
binding.gypto trigger execution during npm install without touchingpackage.jsonscripts. - 2Late May 2026: Miasma variant mutates, targeting 32
@redhat-cloud-servicesnpm 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.mjsand.cursor/rules/setup.mdcbackdoor 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 accountgithub.com/liuende501with 236 credential dead-drop repositories identified.
Phase 2 — The binding.gyp Zero-Click Exploit
INITIAL EXECUTIONEvery 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.
- 1Miasma plants a
binding.gypfile 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 processesbinding.gypto build the native addon. It evaluates the<!()expression, executingnode index.js— the malicious payload — as a side effect of "compiling." - 3The malicious
index.jsis placed at the package root (notdist/index.js), weighing in at 4+ MB — a clear anomaly detectable by build artifact scanning. - 4Stderr is redirected to
/dev/nulland execution is chained with&& echo stub.cto return a valid stub source file name, making the build appear normal to node-gyp.
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.
Phase 3 — 4-Stage Obfuscation Pipeline
EVASIONMiasma'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.
- 1Stage 0 — Preinstall Bootstrap: A 4.29 MB dropper is embedded in the malicious package. The
binding.gyptrigger executesnode 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
IMPACTMiasma'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 Platform | Harvesting Method | Data Stolen |
|---|---|---|
| GitHub | Token validation, GraphQL branch history extraction, Runner.Worker process memory scan via /proc | OAuth tokens, ACTIONS_RUNTIME_TOKEN, ACTIONS_ID_TOKEN_REQUEST_TOKEN, org secrets, Actions secrets |
| npm Registry | /-/whoami validation, OIDC token exchange for elevated publish rights | npm auth tokens, OIDC publish tokens, maintainer package lists |
| AWS | IMDS v2 endpoint (169.254.169.254), ECS task metadata endpoint (169.254.170.2) | IAM access keys, session tokens, Secrets Manager content |
| Azure | IMDS OAuth2 at management.azure.com, graph.microsoft.com, *.vault.azure.net | Managed identity tokens, Key Vault secrets, Azure credentials |
| GCP | metadata.google.internal service-account tokens, Secret Manager, Resource Manager | Service account private keys, OAuth scopes, GCP project secrets |
| HashiCorp Vault | Probed at 127.0.0.1:8200 across multiple token paths | Vault tokens, KV secrets |
| Kubernetes | Service Account token at /var/run/secrets/kubernetes.io/serviceaccount/token | K8s service account tokens, namespace secrets |
| CI/CD | Environment variable scraping | CircleCI tokens, SSH private keys, CLI credentials |
| Local Stores | File system traversal | 1Password, gopass, pass credential managers, browser/wallet data |
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
PROPAGATIONMiasma 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.
- 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/liuende501with 236 programmatically-created credential storage repositories. Stolen tokens double-Base64 encoded in transit. Traffic spoofspython-requests/2.31.0User-Agent. - 4C2 rotates across a pool of 16 attacker-controlled GitHub accounts per session. This distributes the data collection and complicates takedown efforts.
- 1Enumerates all accessible repositories via
/user/reposand/user/orgsusing stolen GitHub tokens. - 2Injects worm source code as
.github/setup.js,.claude/setup.mjs, and.cursor/rules/setup.mdcinto non-protected repository branches via the Git Data API (blob → tree → commit → ref update). - 3Skips protected branches, default branches named
main/masterwhere 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- 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, orautotelfamily 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.gypcontaining<!(nodeornode index.jsin 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 withresults/directories containing JSON files. - 5Review Bun runtime downloads in build system logs. Any
curlorwgetfetching fromgithub.com/oven-sh/bun/releasesduring an npm install operation indicates compromise.
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.
- 1FIRST — Identify honeytoken: Before revoking ANY GitHub tokens, check each token against the IOC list. The token
IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwneris 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.
- 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.jsfiles (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.jsfiles. 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.
- 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| SHA-256 Hash | File | Notes |
|---|---|---|
| 396cac9e457ec54ff6d3f6311cb5cc1da8054d019ce3ffa1de5741506c7a4ea4 | index.js (v1) | @redhat-cloud-services/types |
| d8d170af3de17bb9b217c52aaaffdf9395f35ef015a57ef676e406c121e5e223 | index.js (v2) | @redhat-cloud-services/frontend-components |
| f0641e053e81f0d01fa46db35a83e0a34494886503086866d956d14e81fd3e1c | index.js (v3) | @redhat-cloud-services/rbac-client |
| d5a97614d5319ce9c8e01fa0b4eb06fb5b9e54fa13b23d718174a1546444123b | index.js (v4) | @vapi-ai/server-sdk variant |
| f88258e21592084a2f93a572ade8f9b91c0cd0e242f5cf6121ed7bad0f7bdd1f | index.js (v5) | ai-sdk-ollama variant |
| 25e121e3b7d300c0d0075b33e5eca39a3e6a659fb9cfee52b70ef71686628f1b | index.js (v6) | autotel family variant |
| Type | Indicator | Significance |
|---|---|---|
| GitHub Account | github.com/liuende501 | Primary C2 credential dead-drop — 236 repos |
| File Path | .claude/setup.mjs | Worm backdoor injected into repos via Git API |
| File Path | .cursor/rules/setup.mdc | Worm backdoor targeting Cursor IDE users |
| File Path | .github/setup.js | Worm propagation file in GitHub repos |
| File Content | binding.gyp containing <!(node index.js | Exploit trigger — 100% malicious |
| File Size | index.js > 4MB at package root (not dist/) | Payload dropper — legitimate packages never have this |
| Network | github.com/oven-sh/bun/releases/* download during npm install | Stage 2 Bun runtime download — highly anomalous in CI |
| Network | 169.254.169.254 from npm install process | AWS IMDS credential theft |
| Network | 169.254.170.2 from npm install process | Azure IMDS credential theft |
| Network | metadata.google.internal from npm install process | GCP metadata credential theft |
| Process Chain | node → sh → bun → [payload] | Miasma execution chain — no legitimate use case |
| Campaign Marker | Repo description: "Miasma: The Spreading Blight" | Attacker marker in credential dead-drop repos |
| Search Keyword | thebeautifulmarchoftime in GitHub search | Campaign beacon keyword used by worm to find infected repos |
| npm Scope | Entire @redhat-cloud-services namespace | All packages in this scope across versions 2026-05-xx |
Phase 8 — Detection & Hunt Queries
DETECTIONPhase 9 — MITRE ATT&CK Mapping
ATT&CK| Technique ID | Technique Name | Miasma Implementation |
|---|---|---|
| T1195.001 | Supply Chain Compromise: Compromise Software Dependencies | Poisoned @redhat-cloud-services and 56 other npm packages |
| T1059.007 | Command and Scripting Interpreter: JavaScript | 4-stage JavaScript obfuscation pipeline, Bun runtime execution |
| T1027 | Obfuscated Files or Information | ROT-N + AES-128-GCM + Obfuscator.io + PBKDF2 (200k iterations) |
| T1555 | Credentials from Password Stores | 1Password, gopass, pass credential manager theft |
| T1552.004 | Unsecured Credentials: Private Keys | SSH key theft from CI/CD environments |
| T1528 | Steal Application Access Token | GitHub OAuth tokens, npm OIDC tokens, CI/CD secrets |
| T1087 | Account Discovery | GitHub /user/repos and /user/orgs enumeration |
| T1041 | Exfiltration Over C2 Channel | RSA-encrypted JSON to liuende501 GitHub dead-drops |
| T1543.002 | Create or Modify System Process | sudoers injection: runner ALL=(ALL) NOPASSWD:ALL |
| T1036 | Masquerading | Spoofed [email protected] commits, python-requests User-Agent |
| T1553.006 | Subvert Trust Controls: Code Signing Policy | Forged SLSA provenance via Sigstore/Fulcio/Rekor |
| T1485 | Data Destruction | Honeytoken wiper: rm -rf ~/ and ~/Documents on token revocation |
Phase 10 — Sources & References
SOURCESHunt 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.
"They can't exploit you if you are the Exploit."