Miasma Worm Infects Multiple LeoPlatform npm Packages A Miasma worm variant infected 20 npm packages under the LeoPlatform organization on June 24, 2026, after an attacker compromised a single maintainer's tokens. The malicious payload, a polymorphic credential stealer and self-propagating worm, was delivered via a binding.gyp file that bypasses lifecycle script scanners. Combined weekly downloads of the affected packages total approximately 13,600. Miasma Worm Infects Multiple LeoPlatform npm Packages Table of Contents A Miasma worm variant hit the LeoPlatform npm ecosystem on June 24, 2026. The attacker compromised a single maintainer’s npm and GitHub tokens and used them to publish infected versions of 20 packages in a 3-second burst. The same tokens pushed weaponized GitHub Actions workflows, disguised as Dependabot, to at least three repos. The payload matches the Miasma supply chain attack toolkit /inside-the-miasma-supply-chain-attack-toolkit documented in our earlier source code analysis: a polymorphically packed Bun-based credential stealer and self-propagating worm that targets npm, PyPI, RubyGems, GitHub, AWS, Kubernetes, HashiCorp Vault, and AI coding tool configurations. Paste or upload a lockfile, parsed locally against 20 packages. TL;DR 20 npm packages under the LeoPlatform / LeoInsights org received malicious updates at 2026-06-24T23:04:55Z - Every infected package contains a binding.gyp that triggers the payload during npm install , bypassing lifecycle script scanners - The payload is identical across all 20 packages after decryption same SHA256 , packed with per-package ROT cipher values and AES-128-GCM keys - The compromised maintainer account czirker also pushed orphan snapshot- branches to three GitHub repos, each carrying a 5.2 MB worm payload and a fake “Dependabot Updates” workflow - Combined weekly download count across the 20 packages is roughly 13,600 The 20 infected packages All 20 packages were published within the same 3-second window. The npm registry time metadata confirms they share a single automated publish run: | Ecosystem | Package | Version | | |---|---|---|---| | 1 | npm | rstreams-shard-util | 1.0.1 | | 2 | npm | leo-logger | 1.0.8 | | 3 | npm | rstreams-metrics | 2.0.2 | | 4 | npm | leo-cdk-lib | 0.0.2 | | 5 | npm | leo-auth | 4.0.6 | | 6 | npm | leo-streams | 2.0.1 | | 7 | npm | serverless-convention | 2.0.4 | | 8 | npm | leo-cache | 1.0.2 | | 9 | npm | leo-connector-elasticsearch | 2.0.6 | | 10 | npm | leo-connector-mysql | 3.0.3 | | 11 | npm | leo-connector-redshift | 3.0.6 | | 12 | npm | leo-connector-mongo | 3.0.8 | | 13 | npm | leo-sdk | 6.0.19 | | 14 | npm | serverless-leo | 3.0.14 | | 15 | npm | leo-cli | 3.0.3 | | 16 | npm | leo-config | 1.1.1 | | 17 | npm | leo-cron | 2.0.2 | | 18 | npm | leo-aws | 2.0.4 | | 19 | npm | leo-connector-oracle | 2.0.1 | | 20 | npm | solo-nav | 1.0.1 | | No matching rows | The highest-traffic targets are leo-logger 3,140 weekly downloads , leo-sdk 1,830 , leo-aws 1,730 , leo-config 1,709 , and leo-streams 1,497 . Four packages under the same maintainers were not infected: leo-connector-common , leo-connector-entity-table , leo-connector-postgres , and leo-connector-sqlserver . All four have their npm latest dist-tag pointing to a prerelease version -rc or -beta . The worm likely skips packages where the latest tag is not a stable release. How the infection works Every infected package received the same three modifications compared to its previous clean version. 1. A new binding.gyp file. The file contains a single node-gyp target that uses command expansion to run node index.js during npm install :The < ... syntax is a GYP command expansion https://gyp.gsrc.io/docs/InputFormatReference.md Command-Expansions- that runs a shell command during project generation. npm automatically invokes node-gyp rebuild when a binding.gyp is present, regardless of whether the package.json defines any install or postinstall script. This bypasses tools that only inspect lifecycle scripts. 2. A replaced index.js. The original module code is wiped and replaced with a single-line obfuscated payload of roughly 5.2 MB. The obfuscation has three layers: Each package uses a different ROT value 5, 8, 19, or 23 and a different set of AES-128-GCM keys. After decryption, every package yields the same two blobs: | Blob | Purpose | Decrypted SHA256 | |---|---|---| b | Bun runtime bootstrapper 907 bytes | ceff7c51d70832...ea154108 | p | Worm payload 781,580 bytes | 9f93d77d328338...9a6db015 | The b blob downloads Bun 1.3.13 https://bun.sh from GitHub releases, caches the binary in a temp directory, and exposes a global getBunPath function. The p blob the worm is written to /tmp/p