Miasma: The Spreading Blight — when a trusted npm namespace becomes the supply chain for a cloud-identity worm
1 June 2026. 32 official packages in the npm scope @redhat-cloud-services were compromised with a credential-stealing worm — the campaign calls itself “Miasma: The Spreading Blight” and is a variant of TeamPCP's open-sourced Mini Shai-Hulud. According to OX Security, patient zero was the compromise of a Red Hat employee GitHub account that pushed malicious orphan commits to two RedHatInsights repositories, bypassing code review; Red Hat has confirmed the incident and removed the packages from the npm registry. Every affected package runs a multi-stage obfuscated loader through a preinstall hook on every npm install, harvesting cloud, CI/CD and developer credentials, propagating across npm and GitHub, installing persistence and a destructive dead-man switch. The single most important rule first: isolate affected machines before revoking tokens — otherwise the switch can wipe the home directory.
TL;DR — the 90-second summary
- What happened?
On 01 June 2026, 32 packages in the npm scope
@redhat-cloud-serviceswere compromised with a credential-stealing worm (JFrog analysed 31 malicious versions; aggregate counts cite up to 96 versions). The “Miasma: The Spreading Blight” campaign is a variant of TeamPCP's open-sourced Mini Shai-Hulud. Patient zero: a compromised Red Hat employee GitHub account that pushed orphan commits to two RedHatInsights repos (review bypass); publishing then ran via GitHub Actions OIDC trusted publishing. Reach: ~80,000 (Wiz) to ~116,991 (aggregate) weekly downloads. Red Hat has confirmed the incident and removed the packages from npm.- How severe?
Critical (operational assessment — no CVE/CVSS for this incident class). Automatic execution via
preinstallbefore any application code, a broad credential sweep (GitHub/AWS/GCP/Azure/Kubernetes/Vault/npm/SSH/Docker/GPG/.env), persistence on Linux and macOS, hooks into AI developer tools — and a destructive dead-man switch that can wipe the home directory on token revocation.- Which packages / versions?
32 packages in the
@redhat-cloud-servicesscope, each with a single malicious patch version (incl.frontend-components 7.7.2,rbac-client 9.0.3,host-inventory-client 5.0.3, and the three MCP packageshcc-pf-mcp 0.6.1,hcc-feo-mcp 0.3.1,hcc-kessel-mcp 0.3.1). Full IOC list in the Detection section.- Am I affected as a Moselwal customer?
You are affected if a build, a CI run or a developer workstation installed one of the listed versions on or after 01 June 2026 — directly or transitively. The Red Hat Insights/Cloud Services frontend packages ship inside many OpenShift/RHEL-adjacent frontends and plugins. Check:
npm ls @redhat-cloud-servicesor a lockfile grep across your estate.- Immediate mitigation?
The order is safety-critical: (1) isolate the affected machine from the network, (2) remove persistence (
kitty-monitor/gh-token-monitor), (3) only then rotate all credentials. Revoking tokens before removing persistence can trigger the dead-man switch. In CI, as a stopgap:npm ci --ignore-scripts.- Criticality?
See the hero badge
critical(operational assessment, no official CVSS). Active in-the-wild distribution on disclosure day, destructive payload — the top of the action-pressure scale.
What happened
On 1 June 2026, several research teams independently reported a compromise in the npm scope @redhat-cloud-services. Wiz Research identified at least 32 package releases with unauthorized modifications that do not match the corresponding source repositories; Aikido and JFrog confirmed the picture across more than 30 packages. These are not typosquats but the real, trusted packages under an official, widely used namespace — frontend components, API clients and developer tooling from the Red Hat Cloud Services/Insights ecosystem.
The decisive point is the initial compromise. According to OX Security, patient zero was a compromised Red Hat employee GitHub account that pushed malicious orphan commits to two RedHatInsights repositories, bypassing code review. Publishing then ran via GitHub Actions OIDC trusted publishing — in GitHub Actions environments the worm requests an OIDC token for registry.npmjs.org via ACTIONS_ID_TOKEN_REQUEST_TOKEN/ACTIONS_ID_TOKEN_REQUEST_URL, exchanges it at the npm registry and publishes under that identity, including a Sigstore signature. So no single maintainer lost a password — the build and identity layer itself was subverted. That is exactly what makes the packages so treacherous for classic provenance checks — provenance proves where something was built, not that the build environment was clean.
Red Hat has publicly confirmed the incident: it is aware of the reports about npm packages in its development tooling ecosystem, immediately launched an investigation and removed the packages from the npm registry; the compromise was limited to internal development tooling. According to OX Security, the first commit carrying the string “Miasma: The Spreading Blight” dates back to 29 May 2026 — so the variant was either active for a few days or being tested from then on, before the broad wave became visible on 1 June.
Every compromised package declares a preinstall hook in its package.json that automatically runs node index.js on every install — before any application code. JFrog highlights a strong self-signal: the analysed sample was @redhat-cloud-services/types 3.6.1, a type-only package — and a type package normally has no reason to run a JavaScript installer before installation. The index.js is a 4.2 MB obfuscated blob: the first stage reconstructs JavaScript from a large numeric character array, applies a ROT-style transform and evaluates the result; it then decrypts two AES-128-GCM blobs (a small Bun bootstrapper under /tmp/b*.js and the actual payload under /tmp/p*.js, run with Bun and then deleted). If Bun is missing, the bootstrapper downloads it from GitHub releases (bun-v1.3.13). New in this wave: per Wiz, the worm generates a uniquely encrypted payload per infection, which significantly complicates detection and version tracking.
Technical assessment
Structurally, Miasma is a lesson in what happens when the install phase itself becomes the attack surface. The preinstall hook runs with the installing user's privileges, unsandboxed, before any vetted application code. On a workstation that is the logged-in human with SSH keys, cloud profiles and token caches; on a CI runner it is the build identity context with OIDC tokens, registry credentials and secret-store access. The worm uses both.
The credential sweep is broad and systematic. On the CI side it targets GitHub Actions secrets including GITHUB_TOKEN and ACTIONS_RUNTIME_TOKEN — and, per JFrog, reads GitHub Actions secrets directly from runtime process memory, bypassing log masking. For cloud credentials it collects AWS access keys and session tokens, GCP application-default credentials and service-account key files, and Azure service-principal and managed-identity tokens. It adds HashiCorp Vault tokens, Kubernetes service-account tokens and kubeconfig files, npm and PyPI publish tokens, SSH private keys, Docker registry credentials, GPG keys and any .env file on disk. Where permissions allow, it actively queries the secret stores: AWS Secrets Manager, SSM Parameter Store, Azure Key Vault and GCP Secret Manager.
The new note in this wave, per Wiz, are the added collectors for GCP and Azure cloud identities. Earlier versions mainly extracted secrets; this variant additionally collects all identities the infected machine has access to. The focus shifts from secret theft to access to the cloud itself.
Notable for our context is a camouflage technique: exfiltration traffic is disguised as going to api.anthropic.com/v1/api — a legitimate-looking domain that blends into the network logs of organisations that use Anthropic services. The /v1/api path is not a valid Anthropic route (a GET returns an Anthropic-style 404 not_found_error); the attackers chose it purely as camouflage. We state explicitly: this is an abuse of the domain name as cover, not evidence of any compromise at Anthropic.
Beyond collection, the worm shows active tradecraft. Before acting it checks for endpoint protection (CrowdStrike, SentinelOne, Carbon Black, StepSecurity Harden-Runner) and avoids execution on Russian-language systems — a pattern also seen in the GlassWorm campaigns. On CI runners it attempts privilege escalation by launching a container that bind-mounts the host /etc/sudoers.d and grants the runner passwordless sudo. On GitHub it manipulates Actions: it commits workflows through the createCommitOnBranch mutation so the change appears as a verified, signed commit, converts JavaScript actions into composite actions that install Bun and run the payload, and injects workflows that expose repository secrets as build artifacts. The npm propagation is a small, effective mutation: scripts.preinstall to bun run index.js, dependencies.bun to ^1.3.13, patch version bumped by one, republished. That mutation is the “spreading blight” — a stolen npm publish token becomes the start of the next wave.
For persistence the worm uses a GitHub dead-drop model: public repos described Miasma: The Spreading Blight (repo name following an <adjective>-<noun>-<number> pattern), stolen credentials committed as results/results-*.json. When a commit contains a token it carries the threat marker IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner. It installs kitty-monitor.service (Linux) or com.user.kitty-monitor.plist (macOS), injects hooks into AI developer tools (Claude, Codex, Gemini, Copilot, Kiro, opencode) and adds VS Code folder-open tasks. And it installs a destructive gh-token-monitor: if a stolen GitHub token is revoked before persistence is removed, it can run destructive commands — up to deleting the home directory. Hence the one non-negotiable order: isolate and remove persistence first, then revoke tokens.
Who is affected
| Affected | Not affected | Condition |
|---|---|---|
Builds, CI runs and workstations that installed a listed @redhat-cloud-services version on or after 01 June 2026 (directly or transitively) | Environments that pulled none of the listed versions and keep lockfiles frozen before 01 June | Installation of a malicious patch version since 01 June |
| CI pipelines that run lifecycle scripts (default) | Pipelines using npm ci --ignore-scripts or with install scripts globally disabled | Execution of preinstall hooks |
| OpenShift/RHEL-adjacent frontends and plugins that embed Red Hat Insights/Cloud Services components | Stacks without a @redhat-cloud-services dependency (TYPO3, Sylius, generic Symfony stacks without this frontend tooling) | Presence of the scope in the dependency tree |
Machines with cloud profiles, OIDC tokens, kubeconfig, SSH keys or .env reachable by the installing user | Hermetic builds without credentials in the build context (short-lived, scoped tokens, no secret mount) | Reachability of credentials at install time |
The uncomfortable part is transitivity. The Red Hat Cloud Services frontend components land as an indirect dependency inside larger frontends and plugins — nobody installs @redhat-cloud-services/frontend-components-utilities deliberately, it comes along. An npm ls across the whole estate is therefore more telling than your memory of what you “use directly”. The three MCP packages (hcc-pf-mcp, hcc-feo-mcp, hcc-kessel-mcp) are a separate trigger for anyone embedding MCP servers in their agent setups.
Impact and immediate measures
The impact is not “one compromised package” but “a compromised identity perimeter”. Anyone who installed one of the versions on a machine with cloud access must assume that the reachable GitHub, AWS, GCP, Azure, Kubernetes and Vault credentials have leaked — and in this wave the cloud identities themselves. That raises the incident from “secret rotation” to “identity and permission review”. The worm character makes it worse: a leaked npm publish token is a potential starting point for the next wave at another maintainer. And the destructive gh-token-monitor turns the standard reaction “revoke the token now” into potential self-harm if done in the wrong order.
Operational Decision Block
- Act immediately and in this order if a listed version was installed on a machine with cloud/CI credentials: (1) isolate the machine from the network, (2) remove persistence (
kitty-monitor,gh-token-monitor), (3) only then rotate credentials, (4) rebuild the runner/workstation from a clean image. - Controlled, in a maintenance window, if the scope only appeared in a hermetic build stage without reachable credentials and lockfiles never pulled the malicious versions: lockfile audit, pin to clean versions, no credential reset needed.
- No acute pressure if no
@redhat-cloud-servicespackage is in the dependency tree: scope grep to confirm, review install-script discipline as a precaution.
The order in detail. First, inventory: npm ls @redhat-cloud-services and a grep across all lockfiles against the IOC version list (Detection section). Second, isolation above all: take every affected machine off the network before touching any token — the dead-man switch makes the order non-negotiable. Third, remove persistence: delete kitty-monitor and gh-token-monitor files; inspect injected hooks in .claude/settings.json, .vscode/tasks.json and ~/.config/index.js. Fourth, remove packages and regenerate lockfiles from trusted metadata, pin to clean versions. Fifth, rotate credentials — only now: all exposed GitHub, npm, AWS/GCP/Azure, Kubernetes service-account, SSH, Vault and Docker credentials, after persistence is confirmed removed. Sixth, rebuild runners and workstations from clean images. CI stopgap:npm ci --ignore-scripts until the estate is clean.
This article reflects our technical and strategic assessment. It is not legal advice and not a data-protection impact assessment.
Detection / verification
Detection has two layers: “did I install a malicious version” (the lockfile/inventory question) and “is persistence or exfiltration already running on the machine” (the endpoint/network question). Check both.
Indicators of Compromise (as of 01 June 2026, verified against the JFrog IOC section):
- Campaign markers / dead-drop repos: description
Miasma: The Spreading Blight; result filesresults/results-*.json; token threat markerIfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner; commit messageschore: update dependencies [skip ci],fix: ci. - Network IOCs:
api.anthropic.com/v1/api(port 443, path returns 404 — camouflage);api.github.com/search/commits?q=firedalazer(kitty-monitor C2); GCP user agentgoogle-api-nodejs-client/7.0.0 gl-node/20.11.0 gccl/7.0.0. - File hashes (SHA-256, sample
types 3.6.1):7069e28a5806db4ab0273639667d203f5e31b401d403af7e36d9f360c1f6d655(package metadata),b86c5ae9e95bd841a595440faa3eb6317441e746f241ae8fd641ab59ed1d1966(install loader). - Loader/Bun artifacts:
/tmp/p*.js,/tmp/b-*/bun,/tmp/b-*/b.zip,/tmp/.bun_ran. - kitty-monitor persistence:
~/.config/systemd/user/kitty-monitor.service,~/.local/share/kitty/cat.py,~/Library/LaunchAgents/com.user.kitty-monitor.plist,/var/tmp/.gh_update_state. - gh-token-monitor persistence (dead-man switch):
~/.config/gh-token-monitor/token,~/.config/gh-token-monitor/handler,~/.local/bin/gh-token-monitor.sh. - Injected hooks:
.claude/settings.json,.claude/setup.mjs,.vscode/tasks.json,.github/setup.js,~/.config/index.js.
Affected packages and malicious versions (32 packages, IOC list):
@redhat-cloud-services/chrome 2.3.1
@redhat-cloud-services/compliance-client 4.0.3
@redhat-cloud-services/config-manager-client 5.0.4
@redhat-cloud-services/entitlements-client 4.0.11
@redhat-cloud-services/eslint-config-redhat-cloud-services 3.2.1
@redhat-cloud-services/frontend-components 7.7.2
@redhat-cloud-services/frontend-components-advisor-components 3.8.2
@redhat-cloud-services/frontend-components-config 6.11.3
@redhat-cloud-services/frontend-components-config-utilities 4.11.2
@redhat-cloud-services/frontend-components-notifications 6.9.2
@redhat-cloud-services/frontend-components-remediations 4.9.2
@redhat-cloud-services/frontend-components-testing 1.2.1
@redhat-cloud-services/frontend-components-translations 4.4.1
@redhat-cloud-services/frontend-components-utilities 7.4.1
@redhat-cloud-services/hcc-feo-mcp 0.3.1
@redhat-cloud-services/hcc-kessel-mcp 0.3.1
@redhat-cloud-services/hcc-pf-mcp 0.6.1
@redhat-cloud-services/host-inventory-client 5.0.3
@redhat-cloud-services/insights-client 4.0.4
@redhat-cloud-services/integrations-client 6.0.4
@redhat-cloud-services/javascript-clients-shared 2.0.8
@redhat-cloud-services/notifications-client 6.1.4
@redhat-cloud-services/patch-client 4.0.4
@redhat-cloud-services/quickstarts-client 4.0.11
@redhat-cloud-services/rbac-client 9.0.3
@redhat-cloud-services/remediations-client 4.0.4
@redhat-cloud-services/rule-components 4.7.2
@redhat-cloud-services/sources-client 3.0.10
@redhat-cloud-services/topological-inventory-client 3.0.10
@redhat-cloud-services/tsc-transform-imports 1.2.2
@redhat-cloud-services/types 3.6.1
@redhat-cloud-services/vulnerabilities-client 2.1.8
Check snippets (copy/paste):
# 1) Is the scope in the tree at all?
npm ls @redhat-cloud-services 2>/dev/null || true
# 2) Persistence artifacts on the machine?
systemctl --user list-units 'kitty-monitor*' 2>/dev/null
ls -la ~/Library/LaunchAgents/com.user.kitty-monitor.plist 2>/dev/null
ls -la /tmp/p*.js 2>/dev/null
grep -RIl 'Miasma' ~/.config ~/.claude ~/.vscode 2>/dev/null
# 3) CI: disable hooks (stopgap)
npm ci --ignore-scripts
At GitHub org level: audit logs for newly created repos described Miasma: The Spreading Blight and for unexpected patch-version publishes under your own npm scopes. JFrog detects the packages via Xray (one XRAY ID per package).
Operator recommendation
Mittelstand
For mid-market teams without a dedicated IR team the key message is the order: do not reflexively rotate tokens, but first isolate the machine and remove persistence. In practice: take the affected workstation or runner off the network, remove kitty-monitor/gh-token-monitor, then rotate. If you have no reproducible build, rebuild the machine when in doubt — that is faster and safer than fully cleaning up an active worm.
Enterprise
Larger organisations should check the identity blast radius: which cloud identities and permissions were attached to the machines that built since 01 June? The new GCP/Azure identity collectors make this a reason for a permission review, not just secret rotation. That GitHub Actions secrets are read from process memory also means log masking was worthless as a control here — an argument for short-lived, scoped OIDC federation over long-lived secrets in the runner.
Kubernetes / declarative stacks
Where @redhat-cloud-services components sit in OpenShift console plugins or frontend builds, the check belongs in the image-build path: identify affected layers, rebuild the base/app image, do not patch the running container. Kubernetes service-account tokens and kubeconfigs reachable in affected CI contexts must be treated as compromised and rotated after persistence removal.
What we did — and the bottom line
For the platforms we run we first answered the simple question: does the @redhat-cloud-services scope appear anywhere in the dependency tree? Via the SBOM inventory and a lockfile grep against the IOC version list this can be settled in minutes per stack. For build pipelines we set --ignore-scripts as an immediate stopgap so no preinstall hook runs before the estate is verified.
Methodologically, Miasma confirms three lines we run anyway. First, install scripts are not an implementation detail but an attack surface — lifecycle hooks belong disabled by default in CI. Second, provenance alone is not enough: the @tanstack wave already showed that validly SLSA-attested packages can be malicious when the pipeline is taken over; Miasma confirms it via OIDC trusted publishing. Third, keep build identities short-lived and scoped — a runner with long-lived cloud keys and npm publish tokens is the maximum blast radius. We take the destructive dead-man switch as a reason to sharpen our IR runbooks: “isolate before you rotate” is now the documented default order for worm incidents with persistence.
Bottom line. Miasma is not a flaw in a piece of code but the repeated demonstration that the npm supply chain itself has become the propagation medium — this time via an official, trusted namespace, a hijacked build identity and a payload that takes cloud identities along with it. The most important operational lesson is unspectacular and saves the machine in an emergency: isolate and remove persistence first, then rotate. The structural lesson is the old one, confirmed again: disable install scripts, do not mistake provenance for security, keep build identities short-lived and scoped. Risk soberly: critical for anyone who installed an affected version with credentials in reach since 01 June; a pure inventory-and-discipline matter for everyone else.
Sources
- JFrog Security Research — Shai-Hulud “Miasma: The Spreading Blight” Hits Red Hat npm Packages (01 June 2026; loader chain, Bun staging, OIDC trusted publishing, full IOC/XRAY table, file hashes)
- Wiz Research — Miasma: Supply Chain Attack Targeting RedHat npm Packages (01 June 2026; affected-packages table, GCP/Azure identity collectors)
- Aikido — Red Hat npm Packages Compromised to Spread a Credential-Stealing Worm (01 June 2026)
- The Hacker News — Miasma Supply Chain Attack Compromises Red Hat npm Packages (01 June 2026; patient zero, source synopsis)
- BleepingComputer — Red Hat npm packages compromised to steal developer credentials (01 June 2026; Red Hat statement)
Frequently asked questions about the Miasma / @redhat-cloud-services npm compromise
Is uninstalling the packages and pinning lockfiles enough?+
Only if the hook never ran (e.g. because scripts were disabled). Once preinstall has executed, treat the machine as compromised: remove persistence, rotate credentials after persistence removal, and when in doubt rebuild the runner/workstation from a clean image. Pinning only prevents re-installation; it does not heal an infection that already ran.
Is Anthropic compromised because the traffic goes to api.anthropic.com?+
No. The worm merely disguises its exfiltration traffic with the legitimate-looking domain api.anthropic.com/v1/api to blend into network logs. The /v1/api path is not a valid Anthropic route (a GET returns 404). This is an abuse of the domain name as cover, not evidence of an incident at Anthropic. Defenders should hunt for node/Bun processes contacting this host from CI/workstations.
Are the hcc-pf-mcp/hcc-feo-mcp/hcc-kessel-mcp MCP packages affected?+
Yes. The three MCP packages are on the IOC list with versions 0.6.1 and 0.3.1. Anyone embedding MCP servers from the @redhat-cloud-services scope in an agent setup should check these versions specifically and treat affected machines like any other infection — isolate, remove persistence, rotate.
Does SLSA provenance protect against this compromise?+
No, not on its own. Miasma was published via GitHub Actions OIDC trusted publishing, so the packages carry legitimate pipeline provenance including a Sigstore signature. The @tanstack wave already produced validly attested but malicious packages. Provenance stays useful but does not replace install-time behavioural detection or script restriction.
Why should I isolate the machine before revoking the tokens?+
Because Miasma installs a destructive gh-token-monitor. If a stolen GitHub token is revoked before persistence is removed, the switch can run destructive commands — up to deleting the home directory. So: isolate from the network first, remove kitty-monitor/gh-token-monitor, then rotate.
How do I check whether my builds pulled an affected @redhat-cloud-services package?+
With npm ls @redhat-cloud-services in the project and a grep across all lockfiles (package-lock.json, pnpm-lock.yaml, yarn.lock) against the IOC version list. Because the frontend components land transitively, the lockfile grep is more telling than your memory of direct dependencies. Hits on a listed patch version since 01 June count as compromised.
We assess, mitigate and validate your npm/CI/cloud platforms against supply-chain worms like Miasma.
SBOM inventory against the IOC list, install-script discipline in CI, an isolate-before-rotate runbook, persistence cleanup and controlled credential rotation — in the right order, so the dead-man switch does not fire. Then short-lived, scoped build identities instead of long-lived secrets in the runner.
Platform operations, not advice on paper: we plug into your DevSecOps process and validate mitigations against the documented exploit path. More at DevSecOps and Services.

![[Translate to English:] Foto von Kai Ole Hartwig.](/fileadmin/_processed_/e/9/csm_ole-neu_73323ad80d.jpeg)

