Miasma — Red Hat npm Supply-Chain Credential Worm

Shai-Hulud-family self-propagating npm worm · "Phantom Gyp" install-time execution via weaponized binding.gyp · multi-cloud secret theft (GitHub / npm / AWS / Azure / GCP / Vault / Kubernetes)
Threat
Miasma (Shai-Hulud variant)
Severity
ACTIVE WORM
Type
Supply-chain / package worm
Initial Access
npm install (preinstall + binding.gyp)
Version
v0.1 · 2026-06-21
Author
HuntPack
Confidence
High (7 vendor sources)
01

Executive Summary

Miasma ("The Spreading Blight") is a self-propagating npm supply-chain worm in the Shai-Hulud lineage. On 1 June 2026 it backdoored 32 packages (~96 versions) in the @redhat-cloud-services npm scope — roughly 116,991 weekly downloads — after an attacker hijacked a Red Hat maintainer's GitHub account and pushed orphan commits carrying valid OIDC/SLSA provenance. By 5 June, 57+ packages and 300+ malicious versions had been identified across the wider npm ecosystem.

The worm runs at install time, before any application code, through two mechanisms: a classic preinstall hook ("preinstall": "node index.js") and — in the second wave — "Phantom Gyp": a weaponized binding.gyp whose sources array embeds a node-gyp command-substitution that silently runs index.js during native-module compilation, bypassing detections that only watch npm lifecycle hooks. The dropper (a ~4 MB Caesar-cipher/AES-128-GCM/obfuscator.io payload) downloads a legitimate Bun v1.3.13 binary to /tmp/b-<random>/bun and harvests credentials for GitHub, npm, AWS, Azure, GCP, HashiCorp Vault and Kubernetes from environment variables, cloud metadata services (IMDSv2 169.254.169.254, ECS 169.254.170.2, Vault 127.0.0.1:8200) and on-disk secret files. When it finds publish-capable npm tokens it re-publishes infected packages to propagate. It also plants AI-coding-agent persistence (~/.claude/settings.json SessionStart hooks, .vscode/tasks.json folderOpen tasks) that fire a harvester when a repo is opened in Claude Code / Cursor / VS Code / Gemini CLI, and crossed into PyPI (37 malicious wheels / 19 packages using .pth startup hooks).

Defender priority: This worm executes during dependency install in CI/CD and dev workstations — not at app runtime. The single highest-value detection is node / npm / node-gyp spawning a shell, bun, or a child that touches cloud-metadata IPs or ~/.npmrc/~/.aws/kube/Vault paths during an install. Treat any host that installed an affected @redhat-cloud-services version since 1 June 2026 as credential-compromised: rotate all npm, GitHub, and cloud tokens reachable from that host/runner.

02

Source Review & Web Hunter Notes

TierSourceKey FindingCarry
1Microsoft Security Blog (02 Jun 2026)Per-package SHA256s; preinstall chain node→shell→bun→payload; IMDS/ECS/Vault/K8s harvest; GitHub dead-drop repos described "Miasma: The Spreading Blight"; .github/setup.js injection; runner-memory OIDC token scrape; sudoers write at /mnt/runner.yes
1Mend.io (MSC-2026-6085)"Phantom Gyp" binding.gyp signature; loader + binding.gyp SHA256; bun-v1.3.13 download URL; AES IVs; full metadata-endpoint + env-var literal list; manifest-mismatch detection signal.yes
1Harness.io32 packages / 96 versions; orphan-commit + OIDC/SLSA abuse; "every infection gets its own encryption" (hash evasion); gh auth token harvest.yes
1Phoenix.securityDecrypted helper/main payload SHA256; AI-agent hook paths (Claude/VS Code/Cursor/Gemini); 73 Microsoft repos auto-disabled in 105s; PyPI Hades wave (37 wheels / 19 pkgs / .pth).yes
1Upwind.ioConcrete affected versions (chrome/frontend-components/types/rule-components/rbac-client); .github/setup.js; spoofed User-Agents.yes
2The Hacker News"Miasma: The Spreading Blight" first seen 29 May 2026; api.anthropic.com spoof channel; VS Code runOn: folderOpen; TeamPCP open-sourced Shai-Hulud tooling (attribution caveat).partial
2Unit 42 (npm supply-chain monitoring)Ecosystem context: install-script abuse trend, second-wave package count (57+ / 300+ versions).partial

Provenance note: api.anthropic.com/v1/api appears as a spoofed / dormant exfil channel (Microsoft: noop:true, disabled). It is a legitimate Anthropic host — do not blocklist it. It is carried only as an enrich/context indicator. GitHub, npm registry, Sigstore, and cloud-metadata endpoints are all legitimate services abused as living-off-the-land exfil; detection is behavioral, not domain-blocking.

03

Hunt Brief & Attack Chain

Hunt hypotheses (fidelity-ordered)

  1. H1 (high): A node/npm/node-gyp process spawns bun (or a binary under /tmp/b-*, /var/folders/*/b-*) during dependency install — the Miasma runtime drop. T1059 / T1195.002
  2. H2 (high): A package-manager install tree makes outbound connections to cloud metadata IPs (169.254.169.254, 169.254.170.2) or to local Vault (127.0.0.1:8200) — credential harvest during install. T1552.005 / T1552.001
  3. H3 (high): binding.gyp written/seen on disk whose contents embed a node-gyp command-substitution (<!(node …)) — the Phantom Gyp signature. T1195.002
  4. H4 (med): An install-time child process reads ~/.npmrc, ~/.aws/credentials, kubeconfig, ~/.config/gcloud, SSH keys, or ~/.claude.json. T1552.001
  5. H5 (med): Creation/modification of AI-agent persistence: ~/.claude/settings.json (SessionStart hook) or .vscode/tasks.json (folderOpen) shortly after a clone/install. T1546
  6. H6 (med): An install-time process runs gh auth token, npm whoami/npm token, or queries registry.npmjs.org/-/npm/v1/tokens — token theft / republish staging. T1552.004 / T1195.002
  7. H7 (med): Sudoers tamper on a CI runner: write to /mnt/runner or a sudoers file containing NOPASSWD:ALL for runner. T1548.003
  8. H8 (low): EDR-fingerprinting file reads (/opt/CrowdStrike, /Library/CS/falcon, /opt/sentinelone) by an install-time child. T1518.001

Attack chain

#StepTelemetryHunt Angle
1Maintainer GitHub account hijack; orphan commit republished with OIDC/SLSA provenance(off-endpoint) npm/GitHub auditnpm dist-tag/publish events; new versions of pinned deps
2npm install resolves an infected version; preinstall or binding.gyp fires node index.jsProcessRollup2node-gyp / npm parent → node/sh child at install (Q1, Q3)
3Dropper de-obfuscates, downloads Bun v1.3.13 → /tmp/b-<rand>/bunProcessRollup2 / NetworkConnectIP4bun spawned from node; download from oven-sh/bun release (Q1, Q2)
4Harvest env vars + IMDS/ECS/Vault/K8s + on-disk secretsNetworkConnectIP4 / FileOpeninstall tree → 169.254.169.254 / 127.0.0.1:8200; secret-file reads (Q4, Q5)
5Token theft: gh auth token, npm token endpointsProcessRollup2gh/npm token commands under install (Q6)
6Exfil via GitHub dead-drop repo "Miasma: The Spreading Blight" / .github/setup.jsNetworkConnectIP4 (api.github.com)anomalous repo creation; correlate with cred-access hosts
7Propagate: republish infected packages using stolen publish tokens(off-endpoint) npm auditunexpected publish from CI identity
8Persistence: AI-agent hooks; sudoers write on runnerFileWritten / ProcessRollup2~/.claude/settings.json, tasks.json, /mnt/runner (Q5, Q7)
04

Consolidated IOC Table

Every atomic IOC below traces to a cited Tier-1 source (§18). Per-infection re-encryption means file hashes are low-durability — favor the behavioral indicators (Phantom Gyp signature, bun-from-node, metadata-IP touches). Package versions and the binding.gyp/loader hashes are the most reliable atomic anchors.

TypeValueConfActionContext / Source
npm pkg/ver@redhat-cloud-services/chrome 2.3.1 / 2.3.2 / 2.3.4highhuntInfected v1 wave (Upwind, MS)
npm pkg/ver@redhat-cloud-services/frontend-components 7.7.2 / 7.7.3 / 7.7.5highhuntInfected (Upwind, MS)
npm pkg/ver@redhat-cloud-services/types 3.6.1 / 3.6.2 / 3.6.4highhuntInfected (Upwind, MS)
npm pkg/ver@redhat-cloud-services/rbac-client 9.0.3 / 9.0.4 / 9.0.6highhuntInfected (Upwind, MS)
npm pkg/ver@redhat-cloud-services/rule-components 4.7.2 / 4.7.3highhuntInfected (Upwind)
npm pkg/ver@redhat-cloud-services/remediations-client 4.0.4 / 4.0.5 / 4.0.7highhuntInfected (MS)
npm pkg/ver@redhat-cloud-services/insights-client 4.0.4 / 4.0.5 / 4.0.7highhuntInfected (MS)
npm pkg/ver@redhat-cloud-services/host-inventory-client 5.0.3 / 5.0.4 / 5.0.6highhuntInfected (MS)
npm pkg/ver@redhat-cloud-services/javascript-clients-shared 2.0.8 / 2.0.9 / 2.0.11highhuntInfected (MS)
npm pkg/ver@redhat-cloud-services/notifications 6.9.3highhuntInfected (MS hash list)
npm pkg/ver@redhat-cloud-services/frontend-components-config-utilities 4.11.3highhuntInfected (Phoenix)
npm pkg/ver@redhat-cloud-services/tsc-transform-imports 1.2.2 / 1.2.4highhuntInfected (Phoenix, Harness)
npm pkg/ver@vapi-ai/server-sdk, ai-sdk-ollamahighhuntSecond wave, 3-4 Jun (Mend)
SHA256 (binding.gyp)ef641e956f91d501b748085996303c96a64d67f63bfeef0dda175e5aa19cca90highdetectPhantom Gyp file, 157 B (Mend)
SHA256 (loader)c2a60face766f69f82c972375f35f8ebaa45d6c464176974e631d9a78d6bea0ahighdetectStage-1 loader, 1 Jun wave (Mend); MD5 8cd0b0fbd4232face584c66d9754bf1e
SHA256 (payload)396cac9e457ec54ff6d3f6311cb5cc1da8054d019ce3ffa1de5741506c7a4ea4highdetectremediations-client (MS)
SHA256 (payload)d8d170af3de17bb9b217c52aaaffdf9395f35ef015a57ef676e406c121e5e223highdetectadvisor-components 3.8.2 (MS)
SHA256 (payload)f0641e053e81f0d01fa46db35a83e0a34494886503086866d956d14e81fd3e1chighdetecthcc-kessel-mcp 0.3.4 (MS)
SHA256 (payload)d5a97614d5319ce9c8e01fa0b4eb06fb5b9e54fa13b23d718174a1546444123bhighdetectfrontend-components-testing 1.2.4 (MS)
SHA256 (payload)f88258e21592084a2f93a572ade8f9b91c0cd0e242f5cf6121ed7bad0f7bdd1fhighdetectnotifications 6.9.3 (MS)
SHA256 (payload)25e121e3b7d300c0d0075b33e5eca39a3e6a659fb9cfee52b70ef71686628f1bhighdetectchrome 2.3.4 (MS)
SHA256 (decrypted)ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6medhuntDecrypted Bun helper (Phoenix)
SHA256 (decrypted)0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35medhuntDecrypted main payload (Phoenix)
Behavioral str"sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]highdetectPhantom Gyp signature in binding.gyp (Mend)
Behavioral str"preinstall": "node index.js"highhuntv1-wave preinstall hook (multiple)
String markerMiasma: The Spreading BlighthighhuntDead-drop GitHub repo description (MS, Mend, Harness)
String markerIfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwnerhighhuntHoneytoken/tripwire literal (MS, Mend, Upwind)
File path/tmp/b-<rand>/bun · /var/folders/<…>/b-<rand>/bun · bun.exehighhuntDropped Bun runtime (Mend)
File path/tmp/p<base36>.jsmedhuntTemp payload file (Mend)
URLgithub.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-<os>-<arch>.ziphighenrichLegit Bun release abused as delivery (Mend)
IP169.254.169.254 · 169.254.170.2medhuntAWS IMDSv2 / ECS metadata harvest (Mend)
IP:port127.0.0.1:8200medhuntHashiCorp Vault probe (MS, Mend)
User-Agentpython-requests/2.31.0 · google-api-nodejs-client/7.0.0medenrichSpoofed UA on exfil (MS, Upwind)
Domain (spoof)api.anthropic.com/v1/apilowenrichDormant noop:true channel — legit host, do NOT block (MS)
AdvisoryMSC-2026-6085highenrichMend.io tracking ID
05

Affected Surface & Telemetry Matrix

SurfaceRequired TelemetryPriorityGap Risk
CI/CD build runners (GitHub Actions / GitLab / Jenkins) running npm installProcessRollup2, NetworkConnectIP4, FileOpen on Linux runner sensorsCriticalHigh — ephemeral runners often lack a sensor
Developer workstations (macOS/Linux/Windows) installing Node depsProcessRollup2, NetworkConnectIP4, FileWrittenHighMed — covered if Falcon deployed to dev fleet
npm registry identity / publish tokensnpm audit logs (off-endpoint)HighHigh — not Falcon telemetry; needs npm-side audit
Cloud control planes (AWS/Azure/GCP) reachable from build credsCloudTrail / Azure AD / GCP audit (off-endpoint)HighHigh — correlate post-harvest cloud API use
AI coding agents (Claude Code / Cursor / VS Code / Gemini)FileWritten on settings.json / tasks.json, ProcessRollup2MediumMed — config-write detection is endpoint-visible
Kubernetes service-account tokens / VaultNetworkConnectIP4 to 127.0.0.1:8200, FileOpen on SA token pathsMediumMed
PyPI / Python dev hosts (Hades wave)FileWritten on *.pth in site-packages, ProcessRollup2MediumMed
06

ATT&CK Mapping

TacticTechniqueObserved BehaviorQuery / Control
Initial AccessT1195.002 — Compromise Software Supply ChainInfected @redhat-cloud-services versions republished to npmQ1, Q3 / H-pin deps
ExecutionT1059.007 / T1059.004 — JS / Unix Shellpreinstall + binding.gyp run node index.js → shell → bunQ1, Q3
ExecutionT1059 — Command & Scripting (node-gyp substitution)Phantom Gyp <!(node …) in sources arrayQ3
Credential AccessT1552.005 — Cloud Instance Metadata APIInstall tree hits IMDSv2 / ECS metadataQ2, Q4
Credential AccessT1552.001 — Credentials in FilesReads ~/.npmrc, ~/.aws, kubeconfig, SSH, GCP credsQ4
Credential AccessT1552.004 — Private Keys / T1528 — Steal App Tokengh auth token, npm token endpoints, OIDC scrapeQ6
PersistenceT1546 — Event-Triggered ExecutionAI-agent SessionStart / folderOpen hooks; PyPI .pthQ5
Privilege EscalationT1548.003 — Sudo & Sudo CachingSudoers write runner ALL=(ALL) NOPASSWD:ALL at /mnt/runnerQ7
Defense EvasionT1518.001 — Security Software DiscoveryReads /opt/CrowdStrike, /Library/CS/falcon, etc.Q8
ExfiltrationT1567 — Exfil Over Web ServiceGitHub dead-drop repos / GraphQL commit; spoofed UANative §7
Impact / PropagationT1080 — Taint Shared ContentRepublish infected packages via stolen tokensnpm audit §7
07

Native Audit-Log Hunts (non-CQL)

npm registry / package side

  • Audit your lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml) for any resolved @redhat-cloud-services/* version published on/after 1 Jun 2026; cross-check against §4.
  • npm org: review publish events and token creation for the past 30 days; revoke all granular + legacy automation tokens and require 2FA/trusted-publishing.
  • Grep extracted node_modules for the Phantom Gyp signature and markers: <!(node index.js, Miasma: The Spreading Blight, IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner.
  • Flag any binding.gyp whose sources array contains a <!(...) command-substitution invoking node/sh — legitimate gyp sources are file names, not commands.

GitHub / SCM side

  • Search org for newly created repos with description Miasma: The Spreading Blight or files at results/<timestamp>-<counter>.json / .github/setup.js / injected codeql.yml on branches prefixed oidc- or chore/add-codeql-static-analysis.
  • Review Actions runs that used id-token: write in the window; rotate any OIDC-derived cloud roles.

Cloud control plane

  • AWS CloudTrail: GetCallerIdentity / Secrets Manager / SSM calls from a build identity immediately after an npm install, especially from new IPs/UA python-requests/2.31.0.
  • Azure sign-in logs / GCP audit: token use originating from CI egress IPs shortly after package install.

These are off-endpoint checks the EDR cannot see. Run them in parallel with the CQL hunts (§8) and treat any correlated hit as confirmed compromise.

08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.
Q1 · node/npm/node-gyp spawns bun at install time
CONF HIGHFP LOWCOST LOW

Looks for: a bun binary (or a binary under a /tmp/b-* drop path) whose parent is a Node/npm/node-gyp process — the core Miasma runtime drop. Highest-fidelity signal in the pack.

// HUNT: Miasma runtime drop — bun spawned by node/npm/node-gyp
// MITRE: T1195.002, T1059.007 | CONF: high  FP: low  COST: low
// REQUIRES: ProcessRollup2 (Linux/macOS/Windows)
// FALSE POSITIVES: legitimate Bun-based projects that run bun from node tooling
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ImageFileName=/(\/|\\)(bun|bun\.exe)$/i
| ParentBaseFileName=/^(node|npm|npx|node-gyp|sh|bash|zsh)$/i
| table([ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine, SHA256HashData, aid], limit=200)
Q2 · Install tree reaches cloud metadata / Vault
CONF HIGHFP MEDCOST LOW

Looks for: a Node/bun/package-manager process connecting to IMDS (169.254.169.254), ECS metadata (169.254.170.2), or local Vault (127.0.0.1:8200) — credential harvest during install. FP: SDKs and IaC tooling legitimately read IMDS on cloud hosts; scope to install context and exclude known IaC service accounts.

// HUNT: Miasma credential harvest — metadata/Vault from install runtime
// MITRE: T1552.005, T1552.001 | CONF: high  FP: medium  COST: low
// REQUIRES: NetworkConnectIP4
// FALSE POSITIVES: cloud SDKs / IaC agents legitimately querying IMDS
// TUNING: exclude approved IaC hosts (terraform/ansible runners) by aid or ComputerName
#event_simpleName=NetworkConnectIP4
| ContextBaseFileName=/^(node|bun|npm|node-gyp|python|python3)$/i
| in(RemoteAddressIP4, values=["169.254.169.254","169.254.170.2","127.0.0.1"])
| (RemoteAddressIP4!="127.0.0.1" OR RemotePort=8200)
| table([ComputerName, UserName, ContextBaseFileName, RemoteAddressIP4, RemotePort, aid], limit=200)
Q3 · Phantom Gyp — node-gyp drives node/sh during build
CONF HIGHFP MEDCOST LOW

Looks for: node-gyp (or a gyp build) spawning a node index.js / shell child — the install-time effect of a weaponized binding.gyp command-substitution. FP: native modules with legitimate gyp build steps; pivot on the child reading secrets (Q4) or spawning bun (Q1) to confirm.

// HUNT: Phantom Gyp — node-gyp build executes node/shell child (binding.gyp abuse)
// MITRE: T1195.002, T1059 | CONF: high  FP: medium  COST: low
// REQUIRES: ProcessRollup2
// FALSE POSITIVES: legit native-module compiles that invoke node during gyp
// TUNING: combine with Q1/Q2 hit on same aid; exclude known native-build images
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^(node-gyp|gyp|node)$/i
| CommandLine=/(index\.js|\bsh\b|\bbash\b|-e\s+|child_process)/i
| ImageFileName=/(\/|\\)(node|sh|bash|zsh|bun)$/i
| table([ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine, aid], limit=200)
Q4 · Install-time process reads secret files
CONF MEDFP MEDCOST MED

Looks for: a Node/bun/python child touching ~/.npmrc, ~/.aws/credentials, kubeconfig, ~/.config/gcloud, SSH keys, or ~/.claude.json. FP: CLIs legitimately read their own config; scope to install-tree parents and high-value secret paths.

// HUNT: Miasma secret-file access by install-time runtime
// MITRE: T1552.001 | CONF: medium  FP: medium  COST: medium
// REQUIRES: FileOpenInfo / FileOpen (file-access telemetry enabled)
// FALSE POSITIVES: legit CLI config reads (aws/gcloud/kubectl)
// TUNING: require ContextBaseFileName in node/bun set AND a high-value path
#event_simpleName=/FileOpen|FileOpenInfo/
| ContextBaseFileName=/^(node|bun|npm|python|python3)$/i
| TargetFileName=/(\.npmrc|\.aws(\/|\\)credentials|kubeconfig|gcloud(\/|\\)|\.ssh(\/|\\)id_|\.claude\.json|VAULT_TOKEN)/i
| table([ComputerName, UserName, ContextBaseFileName, TargetFileName, aid], limit=200)
Q5 · AI-agent persistence hook written
CONF HIGHFP MEDCOST LOW

Looks for: a Node/bun process writing ~/.claude/settings.json, .vscode/tasks.json, or a PyPI .pth in site-packages — the AI-agent / Python startup persistence. FP: legitimate editor/agent config saves; scope writer to the install-runtime set and alert on first-write by a node/bun child.

// HUNT: Miasma persistence — AI-agent hook / .pth written by install runtime
// MITRE: T1546 | CONF: high  FP: medium  COST: low
// REQUIRES: FileWritten / NewExecutableWritten
// FALSE POSITIVES: user-driven editor/agent config saves
// TUNING: require writer ContextBaseFileName in node/bun/npm; exclude IDE binaries
#event_simpleName=/FileWritten|NewScriptWritten/
| ContextBaseFileName=/^(node|bun|npm|python|python3)$/i
| TargetFileName=/(\.claude(\/|\\)settings\.json|\.vscode(\/|\\)tasks\.json|site-packages(\/|\\).*\.pth)$/i
| table([ComputerName, UserName, ContextBaseFileName, TargetFileName, aid], limit=200)
Q6 · Token theft — gh / npm token commands at install
CONF MEDFP MEDCOST LOW

Looks for: gh auth token, npm token, or npm whoami executed under a package-install parent — publish-token staging for propagation. FP: CI pipelines legitimately call gh auth/npm whoami; key on these running as a child of an install rather than top-level pipeline steps.

// HUNT: Miasma token theft / republish staging
// MITRE: T1552.004, T1528, T1195.002 | CONF: medium  FP: medium  COST: low
// REQUIRES: ProcessRollup2 (command line visibility)
// FALSE POSITIVES: CI steps that legitimately run gh/npm auth
// TUNING: require ParentBaseFileName in node/npm/node-gyp/sh install context
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^(node|npm|npx|node-gyp|bun|sh|bash)$/i
| CommandLine=/(gh\s+auth\s+token|npm\s+token|npm\s+whoami|registry\.npmjs\.org\/-\/npm\/v1\/tokens)/i
| table([ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine, aid], limit=200)
Q7 · Sudoers tamper on CI runner
CONF HIGHFP LOWCOST LOW

Looks for: a process writing a sudoers entry granting runner NOPASSWD:ALL, or any write to /mnt/runner — Miasma's runner privilege escalation.

// HUNT: Miasma privilege escalation — sudoers NOPASSWD write on runner
// MITRE: T1548.003 | CONF: high  FP: low  COST: low
// REQUIRES: ProcessRollup2 OR FileWritten
// FALSE POSITIVES: rare; legit sudoers automation should be allowlisted
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| CommandLine=/(NOPASSWD:\s*ALL|(\/|\\)mnt(\/|\\)runner|(\/|\\)etc(\/|\\)sudoers)/i
| CommandLine=/(echo|tee|sed|cat|printf|mount)/i
| table([ComputerName, UserName, ImageFileName, CommandLine, aid], limit=200)
Q8 · EDR/security-software discovery by install runtime
CONF MEDFP MEDCOST MED

Looks for: a Node/bun child enumerating EDR install paths (/opt/CrowdStrike, /Library/CS/falcon, /opt/sentinelone, /opt/carbonblack) — Miasma's environment fingerprinting. FP: inventory/asset agents read these paths; scope to node/bun parentage during install.

// HUNT: Miasma security-software discovery
// MITRE: T1518.001 | CONF: medium  FP: medium  COST: medium
// REQUIRES: FileOpen/FileOpenInfo OR ProcessRollup2
// FALSE POSITIVES: inventory/asset agents enumerating security tooling
// TUNING: require ContextBaseFileName node/bun and exclude asset-mgmt agents
#event_simpleName=/FileOpen|FileOpenInfo/
| ContextBaseFileName=/^(node|bun|python|python3)$/i
| TargetFileName=/(\/opt\/CrowdStrike|\/Library\/CS\/falcon|\/opt\/sentinelone|\/opt\/carbonblack)/i
| table([ComputerName, UserName, ContextBaseFileName, TargetFileName, aid], limit=200)

Tuning order: Q1 and Q7 are near-zero-FP — promote first. Q2/Q3 fire on credential harvest and Phantom Gyp; pair them on the same aid for a high-confidence install-time compromise. Q4/Q5/Q6/Q8 are hunt-grade pivots — investigate hits, don't alert blindly.

09

CrowdStrike Custom IOA Recommendations

IOA NamePatternExclusionsAction
Miasma — Bun dropped by Node toolingProcess create: image bun/bun.exe with parent node|npm|node-gyp|npx (from Q1)Allowlist repos that legitimately ship Bun in their buildBlock / Detect-Critical
Miasma — Sudoers NOPASSWD on runnerCommand line matches NOPASSWD:\s*ALL targeting runner or write to /mnt/runner (Q7)Allowlist sanctioned sudoers automationBlock
Miasma — Install runtime hits IMDS/VaultNetwork connect from node|bun to 169.254.169.254/169.254.170.2/127.0.0.1:8200 (Q2)Exclude approved IaC runner aidsDetect-High
Miasma — AI-agent hook write by node/bunFile write to .claude/settings.json or .vscode/tasks.json by node|bun (Q5)Exclude IDE/agent self-writesDetect-High

Promote Q1 and Q7 to blocking Custom IOAs on CI runner host groups first (lowest FP, highest impact). Run Q2/Q5 as Detect-only for 1–2 weeks to baseline before any block.

10

Machine-Readable IOC Appendix

One-click blocks for Falcon IOC Management and your detection backlog. Hashes are sourced (§4/§18) but low-durability (per-infection re-encryption) — prefer the behavioral signatures.

Falcon IOC Management CSVbulk import
type,value,action,severity,expiration,description,tags
sha256,ef641e956f91d501b748085996303c96a64d67f63bfeef0dda175e5aa19cca90,detect,critical,2026-12-21,Miasma Phantom Gyp binding.gyp,campaign:Miasma
sha256,c2a60face766f69f82c972375f35f8ebaa45d6c464176974e631d9a78d6bea0a,detect,critical,2026-12-21,Miasma stage-1 loader,campaign:Miasma
sha256,396cac9e457ec54ff6d3f6311cb5cc1da8054d019ce3ffa1de5741506c7a4ea4,detect,high,2026-12-21,Miasma payload remediations-client,campaign:Miasma
sha256,d8d170af3de17bb9b217c52aaaffdf9395f35ef015a57ef676e406c121e5e223,detect,high,2026-12-21,Miasma payload advisor-components,campaign:Miasma
sha256,f0641e053e81f0d01fa46db35a83e0a34494886503086866d956d14e81fd3e1c,detect,high,2026-12-21,Miasma payload hcc-kessel-mcp,campaign:Miasma
sha256,d5a97614d5319ce9c8e01fa0b4eb06fb5b9e54fa13b23d718174a1546444123b,detect,high,2026-12-21,Miasma payload fe-components-testing,campaign:Miasma
sha256,f88258e21592084a2f93a572ade8f9b91c0cd0e242f5cf6121ed7bad0f7bdd1f,detect,high,2026-12-21,Miasma payload notifications,campaign:Miasma
sha256,25e121e3b7d300c0d0075b33e5eca39a3e6a659fb9cfee52b70ef71686628f1b,detect,high,2026-12-21,Miasma payload chrome,campaign:Miasma
md5,8cd0b0fbd4232face584c66d9754bf1e,detect,high,2026-12-21,Miasma stage-1 loader (MD5),campaign:Miasma
Behavioral Signaturesgrep / IOA / SIEM
# Phantom Gyp — weaponized binding.gyp sources array
"sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]
# v1-wave preinstall hook
"preinstall": "node index.js"
# Dead-drop / tripwire string markers
Miasma: The Spreading Blight
IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner
# Dropped Bun runtime paths
/tmp/b-<rand>/bun
/var/folders/<...>/b-<rand>/bun
bun.exe
/tmp/p<base36>.js
# Behavioral chains
node|npm|node-gyp  ->  bun (or /tmp/b-*/bun)
node|bun  ->  169.254.169.254 | 169.254.170.2 | 127.0.0.1:8200
node|bun  writes  ~/.claude/settings.json | .vscode/tasks.json | site-packages/*.pth
Affected npm Versionslockfile audit
# @redhat-cloud-services scope — published on/after 2026-06-01
@redhat-cloud-services/chrome@2.3.1 @2.3.2 @2.3.4
@redhat-cloud-services/frontend-components@7.7.2 @7.7.3 @7.7.5
@redhat-cloud-services/types@3.6.1 @3.6.2 @3.6.4
@redhat-cloud-services/rbac-client@9.0.3 @9.0.4 @9.0.6
@redhat-cloud-services/rule-components@4.7.2 @4.7.3
@redhat-cloud-services/remediations-client@4.0.4 @4.0.5 @4.0.7
@redhat-cloud-services/insights-client@4.0.4 @4.0.5 @4.0.7
@redhat-cloud-services/host-inventory-client@5.0.3 @5.0.4 @5.0.6
@redhat-cloud-services/javascript-clients-shared@2.0.8 @2.0.9 @2.0.11
@redhat-cloud-services/notifications@6.9.3
@redhat-cloud-services/frontend-components-config-utilities@4.11.3
@redhat-cloud-services/tsc-transform-imports@1.2.2 @1.2.4
# Second wave (2026-06-03/04)
@vapi-ai/server-sdk
ai-sdk-ollama
# Action: pin to last-known-good PRE-2026-06-01 version; rotate all reachable secrets
Enrich-only / Do-NOT-Blockcontext, not blocklist
# Legitimate services abused as LOLBin exfil/delivery — DO NOT blocklist
api.anthropic.com/v1/api        # dormant noop:true spoof channel (legit Anthropic host)
github.com/oven-sh/bun/releases/download/bun-v1.3.13/   # legit Bun release abused
registry.npmjs.org/-/npm/v1/tokens   # token-theft endpoint (legit registry)
fulcio.sigstore.dev / rekor.sigstore.dev   # provenance abuse (legit)
# Spoofed User-Agents (enrich/correlate only)
python-requests/2.31.0
google-api-nodejs-client/7.0.0
# Mend advisory: MSC-2026-6085
11

Detection Validation Gates

GateCheckPass criteria
Telemetry readyProcessRollup2 + NetworkConnectIP4 present on CI runner & dev host groups; FileOpen/FileWritten enabled for Q4/Q5/Q8> 95% of in-scope hosts reporting in last 24h
Benign baselineRun Q1–Q3 over 7 days; catalogue legit Bun projects & IaC IMDS readersAllowlist authored; residual hits investigable by hand
Positive testIn an isolated lab runner, create a benign binding.gyp with a <!(node …) source and a node→bun spawnQ1 and Q3 both fire; correlate on same aid
Cred-access testLab: node process curls 169.254.169.254 + reads a dummy ~/.npmrcQ2 and Q4 fire
PromotionFP rate of Q1/Q7 over baseline window< 1 FP / 1k installs → promote to blocking IOA
12

Hardening — Tiered

Immediate (this week)
  • Disable install scripts in CI — set npm ci --ignore-scripts / npm config set ignore-scripts true for build pipelines. Kills both the preinstall hook and node-gyp execution for pure-JS deps. M1042
  • Pin & freeze — pin every @redhat-cloud-services/* dep to a known-good PRE-2026-06-01 version; commit lockfiles; enable npm audit signatures / provenance verification. M1051
  • Rotate now — for any host/runner that installed an affected version since 1 Jun: revoke & reissue npm tokens, GitHub PATs/Actions OIDC roles, and all cloud creds reachable from that identity. M1027
  • Block IMDS from build runtimes — enforce IMDSv2 hop-limit=1 and deny container/build access to 169.254.169.254 where not required. M1037
Near term (1–4 weeks)
  • Egress-restrict CI — allowlist build-runner egress to the registry + artifact stores only; deny arbitrary GitHub-release downloads (blocks the Bun fetch). M1037
  • Trusted publishing / OIDC — migrate npm publishing to OIDC trusted publishing with required reviewers; remove long-lived automation tokens. M1026 / M1032
  • AI-agent hook hygiene — treat ~/.claude/settings.json and .vscode/tasks.json as sensitive; FIM them and block repo-supplied folderOpen/SessionStart auto-run. M1040
  • Short-lived runner identities — ephemeral, least-privilege runners; no standing cloud roles attached to build hosts. M1018
Strategic (1–3 months)
  • Internal registry / vetting proxy — proxy all npm/PyPI through an internal mirror with version-allowlisting, install-script policy, and provenance gates. M1016
  • Build isolation — run installs in network-segmented, no-secret-mounted sandboxes; inject secrets only at deploy, never at npm install. M1030
  • SBOM + continuous provenance — generate SBOMs per build and alert on dependency drift / unsigned republish. M1051

MITRE mitigations cited as the why; the what is anchored to npm/OpenSSF Secure Supply Chain guidance, CIS Software Supply Chain Security, and cloud-provider IMDSv2 hardening (AWS/Azure/GCP) — see §13 for deployable form.

13

Deployable Playbooks

1 · Harden CI installs (disable scripts + pin)

# .npmrc committed at repo root (and in CI image)
ignore-scripts=true
audit-signatures=true
# CI install step
npm ci --ignore-scripts
# When a dep genuinely needs a native build, run it explicitly + reviewed:
#   npm rebuild <allowlisted-pkg>

2 · Audit lockfiles for affected versions (run on every repo)

#!/usr/bin/env bash
# Flag any resolved @redhat-cloud-services version present in lockfiles.
set -euo pipefail
grep -REn '@redhat-cloud-services/' \
  --include='package-lock.json' --include='yarn.lock' --include='pnpm-lock.yaml' . \
  | grep -Ei 'chrome@2\.3\.|frontend-components@7\.7\.|types@3\.6\.|rbac-client@9\.0\.|rule-components@4\.7\.|remediations-client@4\.0\.|insights-client@4\.0\.|host-inventory-client@5\.0\.|notifications@6\.9\.3|config-utilities@4\.11\.3|tsc-transform-imports@1\.2\.' \
  && echo "[!] Affected Miasma version(s) found — pin to pre-2026-06-01 and rotate secrets" \
  || echo "[ok] No known-affected versions in lockfiles"

3 · Scan extracted node_modules for Phantom Gyp / markers

#!/usr/bin/env bash
# Detect weaponized binding.gyp and dead-drop markers in installed trees.
set -euo pipefail
ROOT="${1:-.}"
grep -REn --include='binding.gyp' '<!\(.*node ' "$ROOT" \
  && echo "[!] Phantom Gyp command-substitution in binding.gyp"
grep -REn -e 'Miasma: The Spreading Blight' \
          -e 'IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner' \
          -e '"preinstall": *"node index.js"' "$ROOT" \
  && echo "[!] Miasma marker found" || echo "[ok] clean"

4 · Enforce IMDSv2 hop-limit on AWS build hosts

# Require IMDSv2 and block container hop to metadata (run per instance / in launch template)
aws ec2 modify-instance-metadata-options \
  --instance-id i-EXAMPLE \
  --http-tokens required \
  --http-put-response-hop-limit 1 \
  --http-endpoint enabled
14

Containment Runbook

PhaseActionsOwnerEvidence
IsolateNetwork-contain (Falcon RTR) any host with a Q1/Q2/Q3 hit. Freeze the affected CI pipeline; quarantine build caches and dropped /tmp/b-*/bun.SOC / PlatformDetection hits, dropped binaries, lockfiles
EradicateRevoke ALL credentials reachable from affected hosts (npm tokens, GitHub PAT/OIDC roles, AWS/Azure/GCP keys, Vault, kube SA tokens). Delete dead-drop GitHub repos. Remove AI-agent hooks & sudoers writes. Pin deps pre-2026-06-01; rebuild images clean.IAM / Cloud / DevRotation tickets, repo deletions, diff of hooks
RecoverRe-issue least-privilege tokens via trusted publishing; restore pipelines with --ignore-scripts + egress allowlist; re-enable runners only after FIM baseline clean.Platform / SecEngClean rebuild logs, new token inventory
VerifyRe-run Q1–Q8 over 72h; confirm no metadata/Vault touches from install runtimes; audit npm publish events for unexpected republish.SOCZero-hit confirmation, npm audit export

Assume full credential compromise for any identity reachable from a host that installed an affected version since 1 Jun 2026. Token rotation is non-optional — the worm's entire purpose is exfil + republish, so stolen publish tokens enable re-propagation even after you clean the endpoint.

15

Detection Coverage Map

TechniqueBehaviorCQLIOACoverage
T1195.002 / T1059Install-time exec (preinstall + Phantom Gyp) → bunQ1, Q3YesGood
T1552.005 / .001Metadata / Vault / secret-file harvestQ2, Q4PartialGood
T1546AI-agent / .pth persistenceQ5YesPartial
T1552.004 / T1528gh/npm token theftQ6NoPartial
T1548.003Sudoers NOPASSWD on runnerQ7YesGood
T1518.001EDR fingerprintingQ8NoPartial
T1567 / T1080GitHub dead-drop exfil & package republishNoGAP — off-endpoint

Known gaps: Exfil-over-GitHub and package republish are not endpoint-visible — covered only by the native npm/GitHub/cloud audit hunts in §7. Ephemeral CI runners without a Falcon sensor are the largest blind spot; prioritize sensor coverage on build infrastructure. Q4/Q5/Q8 depend on file-access telemetry being enabled in the prevention policy. Validation: all gates in §11 must pass before promoting Q1/Q7 to blocking IOAs.

16

Hunt Summary Ticket

TITLE:      Miasma — Red Hat npm Supply-Chain Credential Worm (Shai-Hulud variant)
SEVERITY:   Critical — active self-propagating worm, multi-cloud credential theft
SCOPE:      CI/CD runners + dev hosts running npm install; npm/GitHub/cloud identities
HYPOTHESIS: Install-time exec (preinstall + Phantom Gyp binding.gyp) drops bun and
            harvests GitHub/npm/AWS/Azure/GCP/Vault/K8s secrets, then republishes
            infected packages to propagate.
QUERIES:    Q1 bun-from-node (high)  · Q2 metadata/Vault (high) · Q3 Phantom Gyp (high)
            Q4 secret-file reads     · Q5 AI-agent hooks       · Q6 token theft
            Q7 sudoers NOPASSWD (high) · Q8 EDR discovery
DO FIRST:   Run Q1 + Q7 across CI runner + dev host groups (lowest FP). Pair Q2+Q3 on
            same aid for confirmed install-time compromise.
FINDINGS:   <record aid / ComputerName / package version / dropped bun path>
GAPS:       Exfil-over-GitHub + republish = off-endpoint (see §7). Sensorless ephemeral
            runners = blind spot. Q4/Q5/Q8 need file-access telemetry.
ACTIONS:    Isolate hit hosts; rotate ALL reachable npm/GitHub/cloud tokens; pin deps
            pre-2026-06-01; npm ci --ignore-scripts; restrict CI egress + IMDSv2.
OWNER:      HuntPack
VERSION:    v0.1 · 2026-06-21
17

Changelog

v0.12026-06-21Initial Miasma HuntPack — 8 CQL hunts, 4 IOA recs, sourced IOC appendix (per-package SHA256 + Phantom Gyp signature), tiered hardening, containment runbook. All atomic IOCs traced to Tier-1 vendor sources (MS, Mend MSC-2026-6085, Harness, Phoenix, Upwind).
18

References

TierSourceUsed ForAccess Date
1Microsoft Security Blog — Preinstall Persistence: Red Hat npm MiasmaPer-package SHA256, exec chain, harvest mechanics, dead-drop, sudoers2026-06-21
1Mend.io — Multi-Cloud Credential Stealer (MSC-2026-6085)Phantom Gyp signature, loader/binding.gyp SHA256, bun URL, metadata endpoints2026-06-21
1Harness.io — Inside the Compromise of Red Hat's PackagesScope (32/96), OIDC/SLSA abuse, hash-evasion, gh token harvest2026-06-21
1Phoenix.security — Miasma Shai-Hulud VariantDecrypted payload SHA256, AI-agent hook paths, PyPI Hades wave, 73-repo auto-disable2026-06-21
1Upwind.io — Miasma npm Worm / Red Hat Credential HarvestAffected versions, .github/setup.js, spoofed User-Agents2026-06-21
2The Hacker News — Miasma Supply-Chain AttackTimeline, AI-agent triggers, attribution (TeamPCP), spoof channel2026-06-21
2Unit 42 — Monitoring npm Supply-Chain AttacksEcosystem context, second-wave package counts2026-06-21

Generated 2026-06-21 · HuntPack v0.1 · Defensive hunt/detection/hardening content only.