'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

T1059.007 JavaScript

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

T1567.001 Exfiltration to Code Repository

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

More in supply chain

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.

Further reading

Threadlinqs Intelligence — Real-Time Threat Detection Platform

[ 0 threats ] [ 0 det ] [ CRIT: 0 ] [ HIGH: 0 ]
// threat_feed
$ sort --newest
Showing all threats

Live intelligence console

Threat weather, live.

Every square is one real report, mapped to MITRE ATT&CK and shipped with Splunk SPL, Microsoft KQL and Sigma detections you can copy.

Every threat in the corpus, newest first.

Threat level
Fig. 01 · Threat weatherIndexing the archive…
1 square = 1 threat · click to open

Latest Threats