Threat reportSupply ChainTL-2026-1872
ChainDrop: Massive npm Supply-Chain Infostealer Worm Compromises 1,300+ Packages via Keyv Maintainer Account Hijack
ChainDrop: Massive npm Supply-Chain Infostealer Worm (TL-2026-1872), also tracked as ChainDrop, is a critical-severity supply-chain compromise, first published 2026-08-04 and last reviewed 2026-08-09. It is attributed to Shai-Hulud Campaign with low confidence, affects npm/Node.js Ecosystem keyv, maps to 32 MITRE ATT&CK techniques (T1005, T1027, T1036.005), and is covered by 9 detection rules and 43 indicators of compromise.
- Severity
- CRITICALAssessed severity
- CVEs
- 0None referenced
- Techniques
- 32MITRE ATT&CK
- Actors
- 1Shai-Hulud Campaign
- Detection rules
- 9SPL · KQL · Sigma
- IOCs
- 43Indicators of compromise
Key facts for TL-2026-1872
- Threat ID
- TL-2026-1872
- Also known as
- ChainDrop, Shai-Hulud, Mini Shai-Hulud, Keyv Supply Chain Attack
- Severity
- CRITICAL
- Status
- ACTIVE
- Category
- SUPPLY_CHAIN
- First published
- Last reviewed
- Attribution
- Shai-Hulud Campaign
- Attribution confidence
- LOW
- Motivation
- ESPIONAGE
- Target sectors
- technology, softwaredevelopment, cloudcomputing, finance
- Target regions
- Global
- Detection rules
- 9
- Indicators of compromise
- 43
- Updates
- 2026-08-09 · revalidated 1× · latest source
Malware and tooling in ChainDrop: Massive npm Supply-Chain Infostealer Worm
Malware and tooling: Shai-Hulud, EtherHiding, Shai-Hulud Worm Framework
How ChainDrop: Massive npm Supply-Chain Infostealer Worm works
A self-propagating infostealer worm dubbed ChainDrop — based on the Shai-Hulud malware framework — has compromised over 1,300 npm packages (1,381 versions) by hijacking the GitHub account of the Keyv/cacheable ecosystem maintainer. The worm embeds a Bun runtime dropper via a preinstall script that deploys a multi-target credential stealer against CI/CD runners, developer workstations, cloud platforms (AWS, GCP, Azure), HashiCorp Vault, Kubernetes secrets, and AI-agent credential stores. Exfiltration uses RSA+AES-256-GCM-encrypted envelopes sent to a public GitHub staging repo and the dead-drop domain npm-cache.com, whose address is resolved dynamically from an Ethereum smart contract. Every malicious package carries valid npm OIDC provenance signed by the legitimate GitHub Actions workflow — a critical bypass rendering provenance-based supply chain verification ineffective.
On August 4, 2026 at approximately 09:02 UTC, an unidentified threat actor compromised the GitHub account of Jared Wray, the maintainer of the Keyv caching library (~153.7M weekly downloads) and the broader cacheable ecosystem. Over the next ~4 hours, the attacker pushed poisoned commits directly to main branches across multiple repositories, bypassing branch protection via the compromised account's credentials. The first malicious package published was keyv@6.0.0, which carried a preinstall script (setup.mjs) and an obfuscated 728 KB payload (Math_Symbol.js). Crucially, because the attacker pushed the poisoned release commit through the maintainer's own GitHub Actions workflows, npm's OIDC trusted publishing system and SLSA provenance attestation both registered as fully valid — the attestation faithfully recorded the poisoned commit hash. This demonstrates a critical gap: provenance proves which commit was built but cannot prove the commit was authorized.
The dropper (setup.mjs) is a cross-platform runtime downloader that fetches the legitimate Bun v1.3.13 runtime from the official oven-sh/bun GitHub releases — a living-off-the-land approach. It detects the platform and architecture (Linux x64 glibc/musl, Linux arm64, macOS x64/arm64, Windows x64/arm64), downloads the appropriate Bun artifact, stages it in /tmp/bun-dl-*, and executes Math_Symbol.js via Bun. After execution, it deletes the staging directory. A second variant of setup.mjs (11,017 bytes, SHA-256 fd3ca400) appeared in community-propagated packages, featuring a hand-rolled minimal ZIP extractor as fallback.
The Stage 2 payload Math_Symbol.js (or math_init.js, identical SHA-1 35a672cf) is a Bun-bundled CJS program weighing 727,680 bytes with three layers of obfuscation: a rotated 1,283-entry string table with custom charset decoder, anti-tamper Object.hardening, and AES-256-GCM encrypted configuration blobs. On execution, it reads GITHUB_REF and GITHUB_REPOSITORY for encrypted target matching on special-cased repos, checks for a Russian locale kill switch (LANG set to Russian causes the payload to exit with 'Exiting as russian language detected!'), detaches and self-respawns outside GitHub Actions via spawn(process.execPath) with _NODE_RUNTIME_INIT to survive the parent npm install process, and writes a camouflage lock file at /tmp/tmp.dpkg_<pid>.lock disguised as a dpkg lock.
The payload performs the most extensive credential harvesting observed in a supply-chain worm, targeting: GitHub tokens (PATs ghp_, OAuth gho_, runner ghs_ and JWT OIDC tokens), npm tokens (npm_ format validated against registry.npmjs.org/-/whoami), AWS credentials (env, ~/.aws/credentials, IMDSv2, ECS metadata, Secrets Manager via ListSecrets + GetSecretValue across 16 regions, SSM GetParameters with decryption), GCP credentials (~/.config/gcloud, service account JSON), Azure credentials (~/.azure/accessTokens.json), Kubernetes secrets (in-cluster API enumeration across all namespaces), HashiCorp Vault (token from env or file, Kubernetes auth, AWS IAM auth, mount enumeration + KV v1/v2 path walk), and over 140 filesystem hotspot paths including .npmrc, .git-credentials, SSH keys, Docker config, .env files, shell histories, password-store entries, and AI-agent credential stores (Claude, Codex, Cursor, OpenAI, Anthropic, Gemini, OpenClaw, OpenCode, Hermes, Kiro). Notably, the payload includes a sudo python3 helper that reads the GitHub Actions Runner.Worker process memory via /proc/*/mem to extract all secrets with 'isSecret':true in-scope from active workflow runs.
Self-propagation is the worm's defining feature. Using stolen npm tokens, the worm lists all publishable packages for the victim account via npm API queries, downloads each current tarball, bumps the patch version, injects setup.mjs + math_init.js, adds the preinstall hook, and republishes with self-generated Sigstore + SLSA provenance bundles. Using stolen GitHub ghs_ tokens, it pushes malicious .claude/settings.json and .vscode/tasks.json to any branch across up to 50 branches per repo — ensuring the payload executes when the repo is opened in VS Code or Claude Code without any npm install step. A separate 'Run Copilot' workflow commits a secrets-laundering workflow that writes ${{ toJSON(secrets) }} to format-results.txt and uploads it as an artifact, which the worm then downloads. A token-monitor service (gh-token-monitor.sh) is installed as either a systemd user timer or macOS LaunchAgent that polls api.github.com/user every 60s for 24h and fires an attacker-controlled handler when the token is revoked — effectively punishing credential rotation.
Exfiltration is dual-path. Primary path: AES-256-GCM-encrypted JSON envelopes wrapping gzip-compressed loot, with the AES key itself wrapped with an embedded RSA-4096 public key (RSA-OAEP-SHA256), sent via HTTPS POST to npm-cache.com:443/router. The C2 domain list is resolved dynamically from an Ethereum smart contract (0xE1f2395ee43e45A1556EC6438a88c31B83493103, selector 0x53ed5143) via eth_call against 75 public RPC endpoints, enabling the attacker to rotate infrastructure in real-time. Secondary path: The worm creates public GitHub repos with auto_init, commits harvested data as results-*.json files with the description 'Shai-Hulud: Here We Go Again'. At the time of publication, over 800 such staging repos existed. The C2 response is bidirectional: if it contains a 'code' field, the worm eval()s it — providing live remote-code-execution capability.
The attack propagated from the original 11 packages in the jaredwray/cacheable ecosystem to affect over 868 distinct packages (1,381 versions) across organizations including ServiceTitan (141 packages), OneReach (78), Or-SDK (74), Ornikar (42), Qlik (28), Nebula.js (22), UmaCloud (8), Arv-Bedrock (5), Deliveroo (2), Picsart (2), and others. Combined monthly downloads exceed 2 billion, placing this among the largest supply-chain attacks in history by ecosystem blast radius. The campaign is an evolution of the previously documented Shai-Hulud 2.0 ('The Second Coming', November 2025) with new capabilities including EtherHiding blockchain-based C2, RSA+AES analyst-proof exfiltration envelopes, AI-agent credential targeting, IDE persistence via Claude and VS Code configurations, and a Russian-language kill switch suggesting Russian-speaking operators.
MITRE ATT&CK techniques used in TL-2026-1872
Collection
Defense Evasion
T1027 Obfuscated Files or Information; T1036.005 Match Legitimate Resource Name or Location; T1070 Indicator Removal; T1078 Valid Accounts
Exfiltration
T1041 Exfiltration Over C2 Channel; T1567.002 Exfiltration to Cloud Storage
Persistence
T1053.005 Scheduled Task; T1543.001 Launch Agent; T1543.002 Create or Modify System Process
Execution
T1059.006 Python; T1059.007 JavaScript; T1204.002 Malicious File
Command and Control
T1071.001 Web Protocols; T1102.002 Web Service; T1572 Protocol Tunneling
Discovery
T1087 Account Discovery; T1526 Cloud Service Discovery; T1613 Container and Resource Discovery
Initial Access
T1195 Supply Chain Compromise; T1195.001 Compromise Software Dependencies and Development Tools; T1195.002 Compromise Software Supply Chain; T1199 Trusted Relationship
stealth
T1202 Indirect Command Execution
Credential Access
T1528 Steal Application Access Token; T1552.001 Credentials In Files; T1552.004 Private Keys; T1552.005 Cloud Instance Metadata API
collection
T1560.003 Archive via Custom Method
Resource Development
T1583.001 Acquire Infrastructure; T1588.002 Obtain Capabilities
defense-impairment
Affected products and versions in ChainDrop: Massive npm Supply-Chain Infostealer Worm
- npm/Node.js Ecosystem — keyv
Vulnerable versions: 6.0.0 - npm/Node.js Ecosystem — flat-cache
Vulnerable versions: 6.1.24 - npm/Node.js Ecosystem — file-entry-cache
Vulnerable versions: 11.1.6 - npm/Node.js Ecosystem — cacheable-request
Vulnerable versions: 13.0.20 - npm/Node.js Ecosystem — cacheable
Vulnerable versions: 2.5.1 - npm/Node.js Ecosystem — cache-manager
Vulnerable versions: 7.2.10 - npm/Node.js Ecosystem — ecto
Vulnerable versions: 5.0.1 - npm/Node.js Ecosystem — @cacheable/utils
Vulnerable versions: 2.5.1 - npm/Node.js Ecosystem — @qlik/embed-runtime
Vulnerable versions: 1.6.4 - npm/Node.js Ecosystem — @picsart/ai-sdk
Vulnerable versions: 3.32.2
Remediation for ChainDrop: Massive npm Supply-Chain Infostealer Worm
Immediate actions
- Rotate ALL tokens and credentials exposed on any system that ran npm install on affected packages — GitHub PATs, npm tokens, cloud provider keys, Vault tokens, K8s service accounts
- Rebuild compromised systems from safe backups or from scratch — do not trust current host state
- Audit all GitHub repos for unexpected commits authored as 'claude <claude@users.noreply.github.com>' or containing 'chore: update config' messages
- Search for and remove any .claude/setup.mjs, .vscode/setup.mjs, gh-token-monitor.sh artifacts
- Revoke all GitHub OIDC tokens and npm automation tokens that may have been exposed
Workarounds
- Use npm install --ignore-scripts to prevent preinstall execution
- Apply package version pinning with integrity hash verification for all dependencies
- Use dependency allowlisting to restrict packages to pre-approved registries
Longer-term hardening
- Enforce npm install --ignore-scripts or npm 12+ (which blocks preinstall hooks by default) in CI/CD pipelines
- Implement minimum package release age policies (3-7 day cooldown before allowing fresh packages into builds)
- Deploy egress controls to block unexpected downloads from known-code-distribution origins (github.com/oven-sh/bun) during install steps
- Require branch protection with PR review and signed commits on ALL protected branches, including for maintainer-owned repos
- Inventory and govern AI-agent config directories (.claude/, .vscode/, .cursor/, .codex/) — alert on unexpected config files
Weaknesses (CWE) in ChainDrop: Massive npm Supply-Chain Infostealer Worm
Timeline of ChainDrop: Massive npm Supply-Chain Infostealer Worm
- Team PCP publicly releases the Shai-Hulud worm source code as open-source software, converting the previously targeted tool into commodity attack infrastructure used by follow-on operators.
- C2 domain npm-cache[.]com registered; Ethereum smart contract at 0xE1f2395ee43e45A1556EC6438a88c31B83493103 deployed to mainnet for dynamic C2 domain resolution
- Researchers detect the worm on Backstage/backstage CI/CD runners (CNCF developer portal) — 10 workflow runs matched Bun process contacting 3 Ethereum RPC providers and npm-cache.com within 2 seconds
- At 13:00-14:00 UTC, BleepingComputer, StepSecurity, JFrog, Wiz, Aikido, OX Security, and Socket publish simultaneous public disclosures; total estimated at 868 packages (1,381 versions) compromised with ~2 billion combined monthly downloads
- By 13:45 UTC, worm has propagated to enterprise packages: @servicetitan (141 packages), @onereach (78), @or-sdk (74), @ornikar (42), @qlik (28), @nebula.js (22); organizations including Deliveroo, Picsart, Qlik, ServiceTitan, OneReach, and Ornikar affected
- At 10:39 UTC, npm Security begins unpublishing malicious packages; npm-cache.com added to blocklist
- At 10:25-10:28 UTC, ecto@5.0.1 published via jaredwray/ecto repository
- At 10:06-10:14 UTC, jaredwray/cacheable monorepo compromised: 9 malicious packages including flat-cache@6.1.24, cacheable-request@13.0.20, cache-manager@7.2.10 published
- Between 09:38 and 13:20 UTC, the worm auto-propagates across 433 additional packages (2,201 versions) using stolen npm tokens, bumping patch versions and injecting setup.mjs + math_init.js via the npm publish API
- At 09:35:00 UTC, keyv@6.0.0 published to npm with valid OIDC trusted publishing and SLSA provenance attestation, signed by legitimate GitHub Actions workflows — every poisoned version carries valid provenance
- At 09:23:50 UTC, cover test deleted via commit f97eabc
- At 09:04:30 UTC, camouflage commit d8c850c plants .claude/settings.json, .vscode/tasks.json, and .claude/math_init.js for AI agent/editor persistence
- At 09:02:37 UTC, threat actor pushes poisoned commit ee2681a to jaredwray/keyv main branch, injecting setup.mjs, Math_Symbol.js, fake cover test, and rewritten release gating
- StepSecurity, Kodem, and Aikido publish initial IOC lists, affected-version tables, and first-hour response runbooks.
- Upwind and Snyk publish technical analyses detailing the Ethereum smart-contract C2 resolution (EtherHiding) mechanism and the abuse of trusted npm/GitHub provenance.
- GitGuardian publishes a 'Mini Shai-Hulud' analysis attributing the malware family's source-code lineage to Team PCP's May 2026 open-source release and naming affected downstream namespaces including OneReach, Ornikar, Qlik, and Picsart; attribution of this specific August wave to a named operator remains explicitly unconfirmed per the source.
Update history for TL-2026-1872
- 2026-08-09 — "Mini Shai-Hulud" / ChainDrop npm Supply Chain Worm Compromises keyv, cacheable Family & 800+ Packages via Ethereum-Resolved C2: What changed Exploitability and status unchanged (ACTIVE/ACTIVE). This source rates severity HIGH vs our CRITICAL — treated as a downgrade and NOT applied. Adds a CWE-506 (Embedded Malicious Code) classification, a larger credential-harvest
Sources cited for ChainDrop: Massive npm Supply-Chain Infostealer Worm
- Massive ChainDrop npm supply-chain attack infects hundreds of packages
- ChainDrop npm Worm: Bun-loaded CI/CD credential harvester with Ethereum dead-drop C2
- Major Shai Hulud campaign strikes npm again
- Keyv and Cacheable npm Supply Chain Attack
- Keyv and Friends Compromised in npm Supply Chain Attack
- A New Infostealer Worm Hits npm Affecting Keyv and Cacheable
- Wiz Research IoCs - Keyv Supply Chain Attack
Detection coverage for TL-2026-1872
As of 2026-08-09, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-1872 across Splunk SPL, Microsoft KQL and Sigma, covering 43 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.