On June 10, 2026, the complete source code for the Miasma credential-stealing worm went public on GitHub. Threat actors used compromised developer accounts to publish dozens of repositories titled Miasma-Open-Source-Release before GitHub could pull them. It was the second time this family's source had leaked — the first led directly to more advanced variants and higher attack rates.
Miasma is the third wave of the Shai-Hulud self-propagating worm family. It compromised 96 npm package versions across 32 @redhat-cloud-services packages, deployed 37 malicious PyPI wheels across 19 packages, and injected backdoors into 123+ GitHub repositories. Its core innovation is a binding.gyp-based execution bypass that defeats --ignore-scripts, paired with AI coding agent config injection that survives full node_modules wipes. The campaign uses GitHub's own public API as C2 and deters incident response with a destructive dead-man switch that executes rm -rf ~/ if a stolen token is revoked.
Miasma did not appear from nowhere. It is the third documented iteration of a self-propagating developer-targeting worm family, named after the sandworm of Frank Herbert's Dune.
preinstall lifecycle hooks. Scale jumped to 25,000+ infected repositories with 1,000 new infections per 30 minutes. Added Docker container escapes, destructive sabotage, and GitHub Actions runner persistence. The worm learned to live inside CI/CD.preinstall hook abandoned for a binding.gyp-based bypass that defeats --ignore-scripts entirely. 57 packages compromised in under 2 hours. First supply chain worm to specifically target Claude Code, Gemini CLI, Cursor, and Copilot configs as persistence mechanisms. Source code leaked publicly on June 10, 2026.
The Red Hat @redhat-cloud-services namespace was the primary entry point. Attackers exploited a critical design gap in npm's trusted publishing system.
npm's trust model binds to "repository plus workflow filename" — not to a branch, a ref, or a protected environment. An attacker with write access to any branch can create a throwaway branch, rewrite a CI workflow to exchange a GitHub Actions OIDC token for an npm publish token, and ship a malicious package version with valid Sigstore provenance attestations.
A Red Hat employee's GitHub credentials appeared in infostealer logs as early as April 13, 2026 — six weeks before the attack. The third wave of malicious package versions became the new latest. Upgrading to "latest" during the attack window actively installed the payload. The typical "just upgrade" response was the attack.
oidc-<hex> branches pushed to three RedHatInsights repositories. CI workflows rewritten to self-publishing jobs.@redhat-cloud-services packages published. Each carries valid provenance — compromised versions look cryptographically legitimate. Third wave becomes latest.Wave 3's core innovation — dubbed "Phantom Gyp" by the security community — moved execution from preinstall lifecycle hooks to a binding.gyp file that node-gyp processes automatically during native builds.
The <!(...) syntax is GYP's command expansion. When npm encounters any package containing binding.gyp, it automatically invokes node-gyp rebuild — without any declared lifecycle scripts in package.json. The command fires during the configure phase, before any compilation. Output is silently redirected to /dev/null.
npm install --ignore-scripts blocks lifecycle scripts — preinstall, postinstall, etc. It does not prevent node-gyp from running when a binding.gyp file is present. This is documented npm/node-gyp behavior, repurposed as an attack vector. Version pinning + scanning is the only reliable protection.
eval().node → shell → bun, evading Node-focused security monitoring.Once executing, the payload conducts a systematic sweep of the developer environment across four target layers.
GitHub Actions masks secrets in logs. It cannot protect them from a process reading the runner's memory. The payload reads the Runner.Worker process directly from /proc:
Any secret visible to a GitHub Actions runner — regardless of log masking — should be treated as compromised if the runner executed a package from an affected version range. This includes OIDC tokens, cloud credentials, and npm publish tokens passed as environment variables.
This is what distinguishes Miasma from every prior supply chain attack. The worm specifically targets the configuration files that AI coding assistants read on startup — persistence hooks that survive npm uninstall and a full node_modules wipe.
The worm enumerates all repositories accessible via stolen tokens, reads workflow files via GitHub's GraphQL API, then injects these config files via createCommitOnBranch. 13 AI coding tools are targeted in total — including Copilot, Kiro, and Cline. Analysis confirmed 123+ repositories carrying injected hooks — a floor figure constrained by GitHub code search limits.
The attack surface expanded the moment AI coding tools began reading project-local configuration files and executing hooks automatically. By injecting into .claude/settings.json and equivalents, Miasma achieves persistence that survives package removal, node_modules wipes, and even OS reinstalls if the repository is re-cloned. The infection migrates from the package to the project.
Miasma requires zero dedicated command-and-control infrastructure. Three hardcoded commit search strings act as independent C2 channels against GitHub's own public API.
Three independent C2 channels using GitHub's commit search API — no dedicated infrastructure, no custom domains, no IP-based blocking possible.
Stolen credentials are RSA-4096 + AES-256-GCM encrypted and uploaded as results/results-{timestamp}.json to rotating attacker-controlled public repositories — liuende501 (236+ repos), windy629, and HerGomUli.
Every machine that executed the payload has a token monitoring service running in the background. This is the most operationally dangerous feature of Miasma — it changes incident response order entirely.
The service polls GET https://api.github.com/user every 60 seconds using the stolen GitHub token. If the response is any 4xx status — token revoked — it immediately executes:
The standard incident response playbook — detect, contain, rotate credentials — will trigger the wiper if credentials are rotated before the persistence service is removed. The correct order is: (1) remove the dead-man switch service, (2) remove AI config hooks, (3) only then revoke stolen tokens.
Once credentials are harvested, the worm immediately reuses them across three parallel propagation paths. A documented 49-second sweep across 5 repositories demonstrates how fully automated the replay is.
binding.gyp + index.js · forge Sigstore/SLSA provenance via Fulcio + Rekor · publish · next developer installs, cycle repeats.gem file · inject extconf.rb with equivalent Bun loader (RubyGems' native extension build hook) · repackage and publish.claude/settings.json, .cursor/rules/setup.mdc, .vscode/tasks.json · push via createCommitOnBranch · backdated commits (e.g. 2020-03-09) to evade detectionConcurrent with the npm wave, the same campaign deployed a PyPI variant using a persistence mechanism that predates Python package execution entirely.
37 malicious wheels across 19 packages embedded a *-setup.pth file. Python's site module processes .pth files during interpreter startup — any line beginning with import followed by a space is executed automatically whenever Python starts, without any explicit package import required.
The Hades wave specifically targeted established bioinformatics packages with large cumulative download counts: dynamo-release, spateo-release, coolbox, and napari-ufish. These are trusted, well-known research tools — not obscure packages. The combined wave totaled 448 affected artifacts — 411 npm, 37 PyPI.
Three weeks before the Red Hat npm wave, the same operator hit PyPI with the durabletask Python package (versions 1.4.1–1.4.3). C2 domains were pre-registered May 16 — three days before the attack. This level of operational preparation confirms the campaign was deliberate and staged, not opportunistic.
The stage-2 rope.pyz payload featured a triple-redundant exfiltration chain: primary C2 at check[.]git-service[.]com (AES-256-GCM + RSA-4096), a GitHub dead-drop fallback (searches for FIRESCALE keyword, RSA-verifies URLs), and a last-resort path that creates public repos with random Slavic folklore names (e.g. BABA-YAGA-KOSCHEI-742) and uploads results.json.
The variant also included geotargeted destruction: on Israeli or Iranian locale systems, a 1-in-6 probability triggered audio playback at max volume followed by rm -rf /*. The remaining 5-in-6 deployed persistent backdoor access instead.
The June 10, 2026 leak of Miasma's complete source code is not just a news event — it is a force multiplier for future campaigns. The toolkit contains credential harvesting modules, the binding.gyp injector, the AI config backdoor generator, the dead-man switch installer, and the three-channel GitHub C2 framework. A five-stage build pipeline generates a unique payload per target, making each sample different enough to defeat signature-based detection.
"We didn't see attackers weaponize it" when similar source code was previously disclosed. — Principal Threat Researcher, major cloud security firm
McCarthy's measured counterpoint: sophisticated actors rarely adopt open-sourced malware directly. The real risk is less sophisticated operators running the toolkit as-is — accelerating frequency without needing expertise. Attribution becomes nearly impossible once the code is public. This is the second time this family's source has leaked. The first led to more advanced variants and higher attack rates. History is positioned to repeat.
Eight-step Miasma attack chain — initial credential theft six weeks before the campaign, through OIDC trusted publishing abuse, Phantom Gyp execution, and GitHub-as-C2 to the destructive dead-man switch.
node-gyp rebuild running for packages without known native components
curl, unzip, bun
oven-sh/bun releases to a temp directory mid-install
User-Agent: python-requests/2.31.0 from non-Python processes
DontRevokeOrItGoesBoom, TheBeautifulSandsOfTime, firedalazer
Trojan:JS/ShaiWorm.DAW!MTB or Trojan:JS/ObfusNpmJs
/tmp/p<random>.js, /tmp/b-<random>/bun, /tmp/kitty-<random>
If the dead-man switch is still running when you revoke a stolen GitHub token, it executes rm -rf ~/ within 60 seconds. Remove the monitoring service first. Then remove config hooks. Only then rotate credentials.
systemctl --user list-units | grep -i monitor then stop and disable. macOS: launchctl list | grep -i monitor then unload. Do this on every potentially affected machine before touching any credentials..claude/settings.json (unexpected hooks entries), .vscode/tasks.json (unexpected runOn: folderOpen), remove .cursor/rules/setup.mdc and .gemini/settings.json if not legitimately present.rm -rf node_modules, pin affected packages to known-clean versions, then npm install --ignore-scripts. Remember: this only blocks lifecycle scripts. Pair with scanning..github/workflows/ changes, search GitHub for repos with descriptions matching Miasma: The Spreading Blight or Hades - The End for the Damned.Deep technical analysis of vulnerabilities affecting your infrastructure — beyond CVSS scores to real-world exploitability and impact.
Passive mapping of your external presence — every exposed service, endpoint, and piece of infrastructure visible to the public internet.
Proactive detection of compromise indicators, APT activity, and post-exploitation artifacts across your email and identity infrastructure.
Continuous surveillance of stolen credential markets, threat actor forums, and data leak channels. Know when you're being targeted before it becomes an incident.