All news
supply chain

EdgeProtect

ChainDrop: Self-Propagating npm Worm Compromises 400+ Packages Starting From keyv

Elastic Security Labs and Microsoft detail a Shai-Hulud-style worm that steals npm and GitHub tokens, republishes packages with a preinstall hook and resolves its C2 through an Ethereum contract.

26 September 2026
ChainDrop: Self-Propagating npm Worm Compromises 400+ Packages Starting From keyv

At a glance

1 CVE2 targets1 industry

Vulnerabilities

CVECVSSEPSSKEVPoCPRS risk
CVE-2024-30941090.9%-Available83 · High

Targets & victims

OrganisationSectorRegionStatus
keyvSoftware-confirmed
npmsoftware-confirmed

Industries

Technology

Technology affected

TON · TONnpm · npmGitHub · GitHub ActionsVS Code · VS Codenpm · flat-cachenpm · cacheable-requestnpm · cacheablenpm · keyvnpm · cache-managerEthereum · EVM

Malware & tooling

Shai-HuludChainDropsetup.mjsMath_Symbol.js

Timeline

  1. Compromise

    ChainDrop npm supply-chain compromise

  2. Campaign start

    Elastic Security Labs identified the new Shai-Hulud campaign

Indicators of compromise

  • other0xE1f2395ee43e45A1556EC6438a88c31B83493103
  • domainawqhnjewqjkl[.]icu
  • domainnpm-cache[.]com

ChainDrop: a self-propagating npm worm

Elastic Security Labs identified a new Shai-Hulud campaign on 4 August 2026 and named the worm CHAINDROP. By the time of Elastic's write-up, more than 400 unique npm packages had been compromised. Microsoft published its own analysis the same week, describing the malware as a "Mini Shai-Hulud variant". Neither Elastic nor Microsoft attributes the campaign to a named threat actor.

The campaign began with keyv, a key-value storage library with over 600 million downloads in the previous month according to Elastic. The attackers trojanised the keyv monorepo, backdooring every subpackage. Elastic says the co-owned backdoored packages together account for over 1.3 billion monthly downloads, and Microsoft names keyv, flat-cache and cache-manager among the affected packages. Microsoft notes that many malicious versions had no matching source commit, pull request or tag, indicating the tarballs were modified and published directly.

How the worm works

Malicious releases add a preinstall lifecycle hook to package.json that runs a dropper, setup.mjs, during installation with no further user action. If the Bun runtime is not present, the dropper downloads it from Bun's official GitHub releases and uses it to run an obfuscated JavaScript payload (Math_Symbol.js, or math_init.js in worm-propagated packages). Microsoft reports that the payload exits on Russian-language systems and stays attached in CI/CD runs to reach job secrets and OIDC publishing permissions.

The credential collector looks for npm and GitHub tokens, cloud credentials (AWS, GCP, Azure, Alibaba Cloud), HashiCorp Vault and Kubernetes tokens, SSH keys and AI tooling credentials; Elastic counts over 300 patterns. Stolen data is gzip-compressed and encrypted with a random AES-256-GCM key, which is in turn encrypted with the attacker's hardcoded RSA public key, so only the holder of the private key can read it.

To spread, the worm checks whether a stolen npm token has package-write permission and can bypass two-factor authentication. For each package it can publish, it downloads the latest tarball, injects the payload and loader, adds the preinstall hook, bumps the patch version and republishes. Microsoft adds that where GitHub Actions OIDC publishing is abused, the malicious packages can carry valid provenance.

Persistence in developer tooling

With stolen GitHub credentials, the payload commits hook files into repository branches: a SessionStart hook in .claude/settings.json for Claude Code and a folderOpen task in .vscode/tasks.json for VS Code, each launching a copy of setup.mjs. Elastic says that with a stolen GitHub App token the worm commits these hooks to up to 50 branches per accessible repository, so simply opening an infected repository can infect another developer.

Command and control: an Ethereum dead-drop resolver

ChainDrop does not hardcode its exfiltration domain. It reads the current endpoint from an Ethereum smart contract at 0xE1f2395ee43e45A1556EC6438a88c31B83493103, which lets the operator rotate C2 without changing the payload. Elastic's hunting queries reference the public RPC endpoints eth.llamarpc.com, go.getblock.io and eth-mainnet.nodereal.io. Elastic observed the domains awqhnjewqjkl[.]icu and npm-cache[.]com during detonation, and Microsoft reports the contract returned npm-cache[.]com at the time of its analysis.

If contract lookup fails, the worm searches GitHub commit history for a signed marker (thebeautifulmarchoftime) and accepts a domain only after validating it against an embedded RSA public key. As a last resort it exfiltrates to a public GitHub repository with a Dune-themed name, created from the victim's account with the description Shai-Hulud: Here We Go Again.

Why it matters

In an August 2026 piece on SDLC supply-chain risk, Palo Alto Networks Unit 42 lists ChainDrop alongside earlier incidents that each abused a different weak point: the XZ Utils backdoor (CVE-2024-3094), where an attacker spent years posing as a helpful contributor; the Axios compromise, where hijacked accounts were used to ship malware in a popular library; and the original Shai-Hulud npm worm, which misused install scripts to steal credentials automatically. Unit 42 recommends cryptographic provenance from signed commits through to signed artifacts and SBOMs, plus disabling install scripts, package cooldown periods, restricted CI/CD egress and short-lived OIDC credentials in place of long-lived tokens.

Microsoft advises reviewing lockfiles, artifact repositories and CI caches for the compromised versions, pinning known-good versions, purging npm and yarn caches, rotating credentials from a clean host and hunting for files such as Math_Symbol.js and math_init.js.

Key points

  • Elastic Security Labs identified ChainDrop on 4 August 2026; over 400 npm packages were compromised, starting with the trojanised keyv monorepo.
  • A preinstall hook runs setup.mjs, which fetches Bun if needed and runs an obfuscated credential stealer; the worm republishes every package a stolen token can write to.
  • Persistence comes from hook files committed to .claude/ and .vscode/ in repository branches, so opening an infected repository can re-trigger the payload.
  • C2 is resolved from an Ethereum contract, with a signed GitHub commit marker and a public "Shai-Hulud: Here We Go Again" repository as fallbacks.
  • No named threat actor has been attributed; Microsoft calls it a Mini Shai-Hulud variant.

Further reading & sources