
'ChainDrop' worm compromises hundreds of popular npm packages
ChainDrop is an npm worm that compromised hundreds of packages on 4 August 2026, some with over 150 million weekly downloads, starting from a malicious commit (174f6a5) in the keyv repository. Datadog dissects the Bun-based loader, the obfuscated second stage, credential theft (files, GitHub Actions runner memory, AWS, Kubernetes, Vault), Ethereum smart-contract C2 discovery, AES/RSA exfiltration, an eval channel, and propagation via stolen npm tokens, GitHub branches and Sigstore provenance. IOCs and a list of affected packages are included.
What it is
ChainDrop is a self-propagating npm worm. On 4 August 2026 Datadog found a malicious commit (174f6a5) in the keyv repository, followed minutes later by similar commits in jaredwray/cacheable and jaredwray/ecto. Hundreds of packages were compromised, some with over 150 million weekly downloads. The payload resembles the Shai-Hulud worm, and its fallback exfiltration repositories reuse the description "Shai-Hulud: Here We Go Again".
How it works
Compromised packages carry setup.mjs (an 11 KB loader) and math_init.js (the obfuscated second stage). The loader runs from "preinstall":"node setup.mjs". It uses any bun on the host, or downloads Bun 1.3.13 from GitHub releases without verifying it. Outside CI, the second stage detaches itself and holds a lock file named tmp.dpkg_14527.lock in the temp directory.
It collects credentials from:
- Files: 290 Linux, 129 macOS and 50 Windows path patterns.
- GitHub Actions runner memory: reads
Runner.Workerthroughsudo python3and/proc/<pid>/mem. - AWS: IMDSv2 only, across 17 commercial regions.
- Kubernetes: in-cluster Secrets.
- Vault.
With a classic GitHub token that has workflow scope, it pushes a branch dependabot/github_actions/format/setup-formatter containing .github/workflows/codeql_analysis.yml. That workflow dumps ${{ toJSON(secrets) }} to an artifact, which the worm downloads before deleting the run and branch.
flowchart TD
A[Stolen data ready] --> B{eth_call to contract}
B -->|healthy domain| E[AES-GCM + RSA-OAEP POST]
B -->|fails| C{GitHub commit search}
C -->|signed domain| E
C -->|no domain, ghp_/gho_ token| D[Public Dune-named repo]
E --> F[Response .code is eval'd]C2 discovery works as follows:
- Primary: the malware queries 73 Ethereum RPC endpoints with
eth_callto contract0xE1f2395ee43e45A1556EC6438a88c31B83493103, selector0x53ed5143. It uses the first returned domain that answers/routerwith 400 or 404. - Fallback: it searches GitHub commits for
thebeautifulmarchoftime(with trailing space). It then accepts the markerthebeautifulsnadsoftimefollowed by a Base64 domain and an RSA signature. - Last resort: it creates a public repo with
results/results-<timestamp>-<counter>.jsonfiles. If the victim belongs to no GitHub organization, the token is double-Base64 encoded into the commit, marked withIfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients, so the repo doubles as a token relay.
If the C2 returns HTTP 200 with JSON, the worm runs eval(responseBody.code). The response is unsigned, so the operator can run arbitrary JavaScript on infected hosts.
Propagation uses three paths:
- npm: granular tokens with
bypass_2fa: trueand package-write permission. The worm republishes the latest tarball with the patch version bumped andscriptsreplaced entirely, which can break the victim's own build and test scripts. - GitHub branches: up to 50 branches per repo get
.vscode/tasks.json,.claude/settings.json(a SessionStart hook),.claude/setup.mjs,.claude/math_init.jsand.vscode/setup.mjs. Opening the folder in VS Code or starting a Claude session reruns the loader. - Provenance: this path runs only inside
opensearch-jsrelease-drafter.ymland targets@opensearch-project/opensearch. It adds the optional dependency@opensearch/setuppinned togithub:opensearch-project/opensearch-js#d446803f4c3bc116263faa3499a1d3f95b2825de. Datadog says a valid Sigstore attestation here would bind the malicious build faithfully, so provenance is not a safety verdict.
Preconditions / Affected
- The package manager must run dependency lifecycle scripts for the loader to start.
- Exposed secrets are those reachable from the host's privileges. Environment-scoped GitHub secrets the injected job cannot access stay out of reach.
- Any developer or CI machine that installed a compromised version should be treated as having leaked every credential on it.
What to do
The page's own remediation guidance is thin. It points to a continuously updated list of compromised packages (with a CSV in Datadog's GitHub repository), which the fetched text did not include. It also offers Datadog Code Security and the open source supply-chain firewall (SCFW), which blocks known malicious packages at install time and logs every npm and PyPI install.
Hunt for these indicators:
SHA-256 of exfil RSA public key (DER):
dc1e6a7ddb29390dd53cf1e5aac40ad9204ea7c6b83ef5656e7cb7a796808b67
SHA-256 of fallback-domain verification key:
166be2b7b58a440f7b17520ffb0368be5d89c76661704b4945417eb04b9ada65
<tmpdir>/tmp.dpkg_14527.lock
~/.local/bin/gh-token-monitor.sh
~/.config/gh-token-monitor/{token,handler,started_at}
~/Library/LaunchAgents/com.user.gh-token-monitor.plist
~/.config/systemd/user/gh-token-monitor.service
/tmp/gh-token-monitor.out.log
/tmp/gh-token-monitor.err.logOther signs to look for:
- Unexpected
.claude/or.vscode/files in repositories. - Branches named
dependabot/github_actions/format/setup-formatter. - A
codeql_analysis.ymlyou did not write. - Public repositories with Dune-style names.
- Packages whose
scriptsobject was reduced to a singlepreinstall.
Caveats
- The
gh-token-monitorpaths are described as dormant, so their absence does not clear a host. - The analysis is static. Datadog says it establishes the request sequence for the Sigstore path, not that Fulcio, Rekor or npm accepted any run.
- The "Exiting as russian language detected!" string is dead code, so there is no active geofence.
Organisations named here
- jaredwray/ecto
Technologies named here
- Datadog Code Security
- Bun
- @opensearch-project/opensearch
- Sigstore
- npm
- GitHub
- GitHub Actions
- Ethereum
- keyv
- cacheable
- SLSA
- Datadog Security Research Feed
- Datadog supply-chain security firewall (SCFW)
- GitHub REST Contents API
- jaredwray/cacheable (GitHub repository, similar malicious commits)
- jaredwray/ecto (GitHub repository, similar malicious commits)
- keyv npm package (malicious commit 174f6a5 in its GitHub repository)
- npm provenance / SLSA / in-toto
Techniques named here
- Code obfuscation
- EtherHiding
- Blockchain smart-contract dead drop C2 discovery
- Cloud and cluster secret collection
- Credential harvesting from files
- Detached background execution and single-instance lock
- Hybrid encrypted exfiltration (gzip, AES-256-GCM, RSA-OAEP SHA-256)
- IDE and AI assistant persistence via config files
- Malicious GitHub Actions workflow secret exfiltration
- Memory scraping of Runner.Worker via /proc/<pid>/mem
- Public GitHub repository exfiltration and token relay
- Remote code execution through eval of C2 response
- Self-propagating worm via stolen npm tokens
- Supply chain compromise via npm package poisoning
Threat actors named here
- ChainDrop
- Shai-Hulud
Also named here
- setup.mjs
- math_init.js
Related in Supply Chain


