'ChainDrop' self-propagating worm compromises hundreds of popular npm packages (keyv, cacheable ecosystem) via Bun-loaded credential stealer with Ethereum dead-drop C2
'ChainDrop' self-propagating worm compromises hundreds of (TL-2026-2822), also tracked as ChainDrop, is a critical-severity supply-chain compromise, first published 2026-08-04. It has no confirmed attribution, affects npm / jaredwray keyv, maps to 15 MITRE ATT&CK techniques (T1003.007, T1027, T1059.007), and is covered by 9 detection rules and 26 indicators of compromise.
Key facts for TL-2026-2822
- Threat ID
- TL-2026-2822
- Also known as
- ChainDrop, Shai-Hulud: Here We Go Again, Mini Shai-Hulud (related wave)
- Severity
- CRITICAL
- Status
- ACTIVE
- Category
- SUPPLY_CHAIN
- First published
- 2026-08-04
- Last reviewed
- 2026-08-04
- Attribution confidence
- LOW
- Motivation
- UNKNOWN
- Target sectors
- technology, software-development, cloud, ecommerce, finance
- Target regions
- Global
- Detection rules
- 9
- Indicators of compromise
- 26
Malware and tooling in 'ChainDrop' self-propagating worm compromises hundreds of
Malware and tooling: ChainDrop, Shai-Hulud, Bun v1.3.13
On 2026-08-04 attackers who compromised the jaredwray/keyv maintainer's GitHub account published malicious versions of keyv, cacheable, flat-cache, file-entry-cache and related packages (>150M weekly downloads for keyv alone) through the project's own release pipeline. A preinstall loader (setup.mjs) fetches the Bun runtime and runs an obfuscated stealer (math_init.js / Math_Symbol.js) that harvests npm, GitHub, AWS, Kubernetes, Vault and AI-tool credentials and re-publishes infected packages with stolen npm tokens. Package-count estimates range from ~444 (StepSecurity) to 1,300+ (press).
How 'ChainDrop' self-propagating worm compromises hundreds of works
ChainDrop is a self-propagating npm supply-chain worm that surfaced on 2026-08-04. Attackers took over the GitHub account of the keyv/cacheable maintainer and pushed an unsigned commit (ee2681a, replaying a 27-file delta onto main) adding setup.mjs, Math_Symbol.js and a preinstall script, plus camouflage commits by a fake 'claude' bot adding IDE/AI hooks. keyv@6.0.0 was then published at ~09:35 UTC through the legitimate GitHub Actions OIDC trusted-publishing pipeline, carrying genuine SLSA provenance in Rekor; the same payloads were reused across ten cacheable workspaces (nine versions published 10:09-10:14 UTC) and ecto@5.0.1. Eleven 'worm carrier' packages were hit directly (keyv 6.0.0, flat-cache 6.1.24, file-entry-cache 11.1.6, cacheable-request 13.0.20, cacheable 2.5.1, cache-manager 7.2.10, @cacheable/utils 2.5.1, @cacheable/memory 2.2.1, @cacheable/node-cache 3.1.2, @cacheable/net 2.1.1, ecto 5.0.1). StepSecurity counted 444 poisoned packages / 2,212 malicious versions (433 victim packages republished with stolen credentials, incl. scopes @servicetitan, @onereach, @or-sdk, @ornikar, @qlik, @nebula.js); BleepingComputer and others cite 868-1,300+ packages and ~2 billion monthly downloads. npm began rolling unpublishes at ~10:39 UTC.
Stage 1, setup.mjs, is run by the npm preinstall lifecycle script. It accepts any working 'bun' binary or downloads official Bun v1.3.13 from github.com/oven-sh/bun releases (Linux x64/arm64 glibc/musl, macOS, Windows) with no integrity verification, then executes stage 2 (math_init.js / Math_Symbol.js, ~727 KB, Bun-bundled). Stage 2 is protected by Base91 string tables with 73 alphabet permutations, a PBKDF2-SHA256 (200k iterations) custom cipher and AES-256-GCM+gzip blobs. Outside CI it respawns itself detached (_NODE_RUNTIME_INIT=1 guard, single-instance lock tmp.dpkg_14527.lock) and contains an unreachable Russian-language geofence.
Stage 2 scans the filesystem (290 Linux / 129 macOS / 50 Windows path patterns: env files, shell history, SSH keys, git/npm/PyPI creds, AWS/Azure/GCP, Kubernetes, Docker, Vault, Terraform, CI/CD secrets, Copilot/Claude configs, crypto wallets, VPN configs, /etc/shadow, /proc/self/environ). On GitHub Actions Linux runners with sudo it dumps Runner.Worker memory via /proc/<pid>/mem with an embedded Python script and extracts isSecret:true values (dropping github_token). It walks the AWS credential chain (env, web identity, ECS, IMDSv2, profiles), reads Secrets Manager across 17 regions and SSM Parameter Store with decryption, queries STS, dumps in-cluster Kubernetes Secrets and HashiCorp Vault KV values. With a classic GitHub token holding workflow scope it pushes a branch (dependabot/github_actions/format/setup-formatter) with a workflow (codeql_analysis.yml, named 'Run Copilot') that writes toJSON(secrets) to format-results.txt as an artifact, downloads it and deletes the run and branch.
Propagation is triple-pronged: (1) stolen granular npm tokens with bypass_2fa and write permission are used to download the latest tarball, inject setup.mjs/math_init.js, replace scripts with {"preinstall":"node setup.mjs"}, bump the patch version and republish; (2) with GitHub credentials it commits .vscode/tasks.json, .claude/settings.json, .claude/setup.mjs, .vscode/setup.mjs and .claude/math_init.js to up to 50 branches per repo, so the loader re-runs when a developer opens the folder in VS Code or starts a Claude session (cross-linked persistence); (3) when running in an opensearch-js release-drafter workflow it mints a valid Sigstore/SLSA provenance and OIDC npm publish token to publish a poisoned @opensearch-project/opensearch with an optional dependency pinned to a GitHub commit.
C2: stage 2 calls eth_call (selector 0x53ed5143) on Ethereum contract 0xE1f2395ee43e45A1556EC6438a88c31B83493103 across 73-75 public RPC endpoints to retrieve current C2 domains, health-checks GET /router (HTTP 400/404 = healthy) and POSTs an RSA-OAEP-SHA256 + AES-256-GCM encrypted, gzipped JSON envelope to /router. The response may carry a 'code' field that is passed to eval() (unsigned, arbitrary remote JavaScript execution). Fallback: GitHub commit search for 'thebeautifulmarchoftime' with RSA-signed commit markers, and GitHub exfiltration repositories (Dune-themed names, description 'Shai-Hulud: Here We Go Again') with a token-relay marker in commit messages. Unit 42 found 453 public exfiltration repositories, domains registered 2026-05-22 and a resolver contract deployed 2026-05-25, and a new DGA-like C2 domain awqhnjewqjkl.icu registered on 2026-08-04.
Attribution: none confirmed. Tooling overlaps Shai-Hulud / Shai-Hulud 2.0 / Mini Shai-Hulud (Bun at preinstall, isSecret:true Runner.Worker memory grep, self-republish with stolen tokens, Bun 1.3.13 pin, PBKDF2 decoder); Unit 42 states it cannot definitively attribute it to TeamPCP. Dormant token-monitor persistence (gh-token-monitor LaunchAgent/systemd) is embedded but not invoked; OPSWAT notes the malware may monitor for credential revocation, so image systems before rotating.
MITRE ATT&CK techniques used in TL-2026-2822
Credential Access
T1003.007 Proc Filesystem; T1528 Steal Application Access Token; T1552.001 Credentials In Files; T1552.005 Cloud Instance Metadata API; T1552.007 Container API; T1555.006 Cloud Secrets Management Stores
Defense Evasion
T1027 Obfuscated Files or Information
Execution
Command and Control
T1071.001 Web Protocols; T1102.001 Dead Drop Resolver; T1573.002 Asymmetric Cryptography
Initial Access
T1195.002 Compromise Software Supply Chain
Persistence
T1546 Event Triggered Execution
Lateral Movement
T1550.001 Application Access Token
Exfiltration
Affected products and versions in 'ChainDrop' self-propagating worm compromises hundreds of
- npm / jaredwray — keyv
Vulnerable versions: 6.0.0 - npm / jaredwray — cacheable ecosystem (cacheable, @cacheable/memory, @cacheable/utils, @cacheable/node-cache, @cacheable/net, cache-manager, cacheable-request, flat-cache, file-entry-cache, ecto)
Vulnerable versions: cacheable@2.5.1; @cacheable/memory@2.2.1; @cacheable/utils@2.5.1; @cacheable/node-cache@3.1.2; @cacheable/net@2.1.1; cache-manager@7.2.10; cacheable-request@13.0.20; flat-cache@6.1.24; file-entry-cache@11.1.6; ecto@5.0.1 - npm (worm-republished victim scopes) — @servicetitan, @onereach, @or-sdk, @ornikar, @qlik, @nebula.js, Picsart, Deliveroo-associated packages and others
Vulnerable versions: patch-bumped versions published 2026-08-04
Remediation for 'ChainDrop' self-propagating worm compromises hundreds of
Patches
- Pin to last known-good versions preceding the 2026-08-04 releases and consume the maintainers' clean re-releases once published
Immediate actions
- Identify installs of the malicious versions (keyv@6.0.0, flat-cache@6.1.24, file-entry-cache@11.1.6, cacheable-request@13.0.20, cacheable@2.5.1, cache-manager@7.2.10, @cacheable/*, ecto@5.0.1 and republished victim packages) via SBOM/lockfiles; purge lockfiles, caches, mirrors and tarballs
- Image affected hosts/runners before revoking credentials (malware may monitor for revocation), then rotate all npm, GitHub, AWS, Kubernetes, Vault, SSH and cloud credentials reachable from them
- Block C2 domains npm-cache.com, pypi-get.com, js-mirror.com, awqhnjewqjkl.icu at DNS/SNI (avoid IP blocking: Cloudflare CDN)
- Search GitHub for repositories described 'Shai-Hulud: Here We Go Again' and commits containing the IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients / thebeautifulmarchoftime markers
- Hunt for .vscode/tasks.json, .claude/settings.json, setup.mjs, math_init.js, Math_Symbol.js and .github/workflows/codeql_analysis.yml containing toJSON(secrets); remove malicious branches such as dependabot/github_actions/format/setup-formatter
Workarounds
- Monitor the Ethereum resolver contract 0xE1f2395ee43e45A1556EC6438a88c31B83493103 for domain changes
- Alert on bun processes executing math_init.js/Math_Symbol.js and on sudo python3 reading /proc/<pid>/mem of Runner.Worker
Longer-term hardening
- Use npm install --ignore-scripts / pnpm script allow-lists and a package-age (cooldown) policy for new releases
- Enforce egress filtering and ephemeral, least-privilege CI runners; avoid passwordless sudo on runners
- Prefer short-lived, workload-bound credentials (OIDC) over long-lived npm/GitHub tokens; require granular tokens without bypass_2fa
- Treat SLSA provenance as evidence not a safety verdict: review source, workflow and artifact referenced by attestations
- Review repo-level IDE/AI-agent config (.vscode/tasks.json, .claude/settings.json) in code review and EDR policy
Weaknesses (CWE) in 'ChainDrop' self-propagating worm compromises hundreds of
CWE-506, CWE-494, CWE-522
Timeline of 'ChainDrop' self-propagating worm compromises hundreds of
- Shai-Hulud 1.0 npm worm wave (September 2025); Shai-Hulud 2.0 'The Second Coming' follows in November 2025 and shares the Bun-at-preinstall, Runner.Worker memory scraping and self-republishing design (OPSWAT, StepSecurity)
- Earliest public GitHub exfiltration repository identified by Unit 42 (Mini Shai-Hulud Wave Four period)
- Three C2 domains (npm-cache.com, pypi-get.com, js-mirror.com) registered within 8 seconds (13:40:28-13:40:36 UTC)
- Ethereum resolver contract 0xE1f2395e...3103 deployed and domains written to it; list narrowed to npm-cache.com about 2h35m later
- Datadog Security Labs, StepSecurity, Unit 42, Aikido, Wiz, Socket and others publish analyses; Unit 42 identifies 453 public exfiltration repositories and new C2 domain awqhnjewqjkl.icu (registered 2026-08-04 via NameSilo)
- ~10:39 UTC: npm begins rolling unpublish of malicious versions
- From 09:38 UTC: automated second-wave propagation republishes hundreds of victim packages with stolen npm tokens (@servicetitan, @onereach, @or-sdk, @ornikar, @qlik, @nebula.js, Picsart and others)
- 10:06-10:14 UTC: payloads reused across ten cacheable workspaces and nine versions published; ecto@5.0.1 published ~10:28 UTC
- 09:29-09:35 UTC: malicious keyv@6.0.0 published through GitHub Actions OIDC trusted publishing with genuine SLSA provenance
- 09:02 UTC: unsigned commit pushed to jaredwray/keyv main adding setup.mjs, Math_Symbol.js and preinstall script via compromised maintainer account; camouflage 'claude' bot commits add IDE/AI hooks
Sources cited for 'ChainDrop' self-propagating worm compromises hundreds of
- 'ChainDrop' worm compromises hundreds of popular npm packages (Datadog Security Labs)
- ChainDrop npm Worm: Bun-loaded CI/CD credential harvester with Ethereum dead-drop C2 (StepSecurity)
- ChainDrop: Inside a Self-Propagating npm Worm (Unit 42)
- Massive ChainDrop npm supply-chain attack infects hundreds of packages (BleepingComputer)
- ChainDrop: The Mini Shai Hulud npm worm's latest wave hits keyv and cacheable (Expel)
- Shai-Hulud Returns: ChainDrop Worm Hits npm, Infecting Hundreds of Packages (OPSWAT)
- ChainDrop npm Worm Hits 1,300 Packages and 2 Billion Monthly Downloads (protect.computer)
- ChainDrop npm worm hits 400+ packages (SupplierShield)
More in supply chain
- Bitget $387.5M Cryptocurrency Theft via Third-Party Security Product Zero-Day (Suspected DPRK / TraderTraitor)
- Mini Shai-Hulud: Compromised @antv npm Packages Steal Developer and CI/CD Credentials (TeamPCP)
- MALFEX: Malicious npm postinstall supply-chain campaign delivering Overlord RAT and movinlike stealer
- PhantomSub: 101 Malicious npm Baileys Forks Force Developers' WhatsApp Accounts into Attacker-Controlled Groups/Channels
- Re-Enabled actions-cool GitHub Actions (issues-helper, maintain-one-comment) Resume Executing Mini Shai-Hulud CI/CD Credential-Theft Payload
Detection coverage for TL-2026-2822
As of 2026-08-04, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-2822 across Splunk SPL, Microsoft KQL and Sigma, covering 26 indicator(s) of compromise. The whole corpus is readable without an account; a free account unlocks full detection query text in Splunk SPL, Microsoft KQL and Sigma; paid tiers add raw indicator values, correlation and the MCP server. Threadlinqs MCP server · View plans.