Miasma npm Worm Hits LeoPlatform Packages

Date Observed: June 24, 2026 (LeoPlatform wave); follow-on @immobiliarelabs wave June 26, 2026
Ecosystem: npm (primary); propagation logic also targets PyPI, RubyGems, and Go
Targets: LeoPlatform / RStreams maintainer account (czirker); ~20 leo-* and rstreams-* packages, plus later @immobiliarelabs Backstage plugins
Attack Type: Self-propagating supply chain worm delivered through a build-time binding.gyp install hook (Mini Shai-Hulud / Miasma family)
Impact: Cloud and registry credential theft, GitHub-based exfiltration, and downstream worm propagation

Key Takeaways

  • A new Miasma worm variant (“Alright Lets See If This Works“) compromised about 20 LeoPlatform and RStreams npm packages (some counts run to 23 across the wave) on June 24, 2026, all published from a single hijacked maintainer account in a multi-second burst.
  • Execution is triggered by a planted binding.gyp file that abuses node-gyp shell expansion, so the payload runs during npm install even with no package.json lifecycle scripts and with –ignore-scripts set.
  • The payload runs under the Bun runtime to evade Node-focused monitoring, harvests cloud and registry credentials, and exfiltrates through the victim’s own GitHub token rather than an attacker domain.
  • It is self-propagating: with stolen npm tokens it republishes to other packages the victim maintains, extending the worm across the registry.
  • As of publication, no CVE or GHSA exists. This is account compromise, not a software flaw, so vulnerability scanners had nothing to match.

Introduction

On June 24, 2026, attackers published malicious versions of roughly 20 npm packages from the LeoPlatform and RStreams ecosystems, an AWS-native event-streaming stack used by Node SDK developers. Every package traced back to one compromised maintainer account, czirker, with the versions pushed within a multi-second window. Researchers tracked the campaign as a new variant of the Miasma worm, tagged in its own code with the string “Alright Lets See If This Works” as reported by Socket.

The campaign is a continuation of the Miasma and Hades supply chain worms documented earlier in 2026. Researchers track Miasma as part of the Mini Shai-Hulud family, a lineage of self-propagating npm worms active since late 2025. It pairs a stealthy build-time execution trigger with credential theft and registry self-propagation, making it a direct threat to CI/CD pipelines that pull these packages.

Scope and Impact of the Attack

The initial wave hit core LeoPlatform packages including leo-sdk, leo-cli, leo-auth, leo-aws, leo-logger, the leo-connector-* family, and rstreams-* utilities. SafeDep put combined volume at roughly 13,600 weekly downloads across the affected packages. Socket flagged additional compromised packages outside the Leo namespace, including prism-silq- and two hexo-* packages — published by a separate npm account (llxlr) rather than the compromised czirker maintainer, plus a related malicious Go module (github.com/verana-labs/verana-blockchain).

A follow-on wave on June 26, 2026, compromised four @immobiliarelabs Backstage plugins (GitLab and LDAP-auth, backend and frontend), with multiple historical versions republished inside a 30-second window. StepSecurity confirmed the same Miasma tradecraft, linking both waves to one operation.

How the Attack Works

Stage 0: Build-time execution via binding.gyp

Each poisoned package added two files: a roughly 5 MB obfuscated index.js and a binding.gyp manifest. The manifest’s sources field abuses node-gyp’s shell-exec syntax, <!(node index.js > /dev/null 2>&1 && echo stub.c), so node-gyp runs index.js at install time during its automatic native-addon rebuild. Because the trigger lives in binding.gyp and not in a preinstall/postinstall script, it slips past lifecycle-script scanners and also survives npm install –ignore-scripts.

Stage 1: Deobfuscation and Bun staging

The index.js payload is wrapped in layered obfuscation: a ROT-style Caesar cipher, AES-128-GCM decryption, and an obfuscator.io string table. After decoding, the loader downloads the legitimate Bun runtime (v1.3.13) from the official oven-sh/bun GitHub releases, writes the decrypted worm to a temporary file such as /tmp/p<random>.js, and runs it under Bun. Analysis of the @immobiliarelabs wave notes this is deliberate evasion: Bun does not honor the –require hook interception many Node security tools rely on.

Stage 2: Credential theft and exfiltration

The worm sweeps the host for credentials: GitHub PATs, OIDC and runner tokens, npm, PyPI, RubyGems, and JFrog tokens, AWS keys (environment, IMDS, ECS metadata, SSM, Secrets Manager), GCP and Azure credentials, HashiCorp Vault and Kubernetes tokens, SSH keys, and password-manager stores. On GitHub-hosted runners, StepSecurity observed the worm reading Runner.Worker process memory through /proc//mem to recover masked GitHub Actions secrets.

Exfiltration is a GitHub “dead drop.” The malware uses the victim’s own GitHub token to create repositories and commit encrypted credential envelopes, so no external attacker domain is contacted. Researchers tracked the operation through commit markers including “RevokeAndItGoesKaboom” and “TheBeautifulSandsOfTime,” and counts of public repositories carrying these markers ran into the hundreds at disclosure.

Propagation and Persistence

With recovered npm tokens, the worm republishes malicious versions to other packages the victim maintains. It plants persistence hooks in AI coding-assistant configurations (Claude Code, Cursor, VS Code, GitHub Copilot, and others), so a developer session re-triggers the payload.

Why this Matters to DevOps and DevSecOps Teams

This attack lives entirely inside the build. The trigger fires during dependency installation on a CI runner, the most privileged and credential-rich point in the pipeline. A single npm install of a transitively pinned leo-* package is enough to expose cloud keys, registry tokens, and Actions secrets, and the self-propagation logic turns one compromised runner into a vector for the next package.

Why Existing Controls Miss This

There is no CVE or GHSA for these versions, so software composition analysis and vulnerability scanners had no signature to match while the attack was live. Lifecycle-script scanners miss the binding.gyp trigger because it is not a declared script, and –ignore-scripts does not stop it. Running the payload under Bun bypasses Node-based runtime monitors. Because exfiltration rides the victim’s legitimate GitHub token to github.com, egress filtering that allows normal GitHub traffic sees nothing unusual. The controls most teams rely on were each blind to a different stage.

How InvisiRisk Protects Against This Attack

The InvisiRisk Build Application Firewall enforces policy on build behavior in real time, which addresses the stages scanners miss.

  • Stability Buffer: Newly published packages are blocked for a configurable window (default 48 hours) before a build can consume them. The Miasma versions were pulled in within seconds of publication; halting fresh releases blocks freshly weaponized packages from reaching the runner.
  • Unauthorized API Action Enforcement: The BAF enforces policy on outbound API calls during builds. PUT/POST operations that create repositories or push commits outside the expected build scope are blocked, which directly disrupts the GitHub dead-drop that creates repositories and commits stolen credentials.

This is the same build-time enforcement model that contains earlier worms in this family, including the Shai-Hulud npm worm and the Red Hat Miasma compromise. For teams hardening their pipelines, InvisiRisk’s CI/CD security for DevSecOps covers the broader control set.

Why Build-Time Defenses Matter

proves that an attacker no longer needs a vulnerability or a declared install script to compromise a pipeline: a planted binding.gyp and a stolen maintainer token are enough. Build-time enforcement is the layer that sees the install hook fire, the unexpected repository creation, and the outbound exfiltration as they happen. If your runners pull leo-* or rstreams-* packages, pin lockfiles to versions published before June 24, 2026, treat the build itself as a control point rather than a trusted zone, and treat any environment that installed an affected version as compromised: preserve logs, remove the malicious versions and the persistence hooks (including AI coding-assistant configs) first, then rotate all exposed tokens from a clean machine — not from the potentially infected host.