Threat reportSupply ChainTL-2026-1872

ChainDrop: Massive npm Supply-Chain Infostealer Worm Compromises 1,300+ Packages via Keyv Maintainer Account Hijack

criticalACTIVE

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

T1005 Data from Local System

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

T1601 Modify System Image

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

CWE-506

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

Sources cited for ChainDrop: Massive npm Supply-Chain Infostealer Worm

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.

9 detection rules (Splunk SPL, Microsoft KQL, Sigma) · Blue and above. Compare plans
43 indicators of compromise · Red and above. Compare 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 level
Fig. 01 · Threat weatherIndexing the archive…
1 square = 1 threat · click to open

Latest Threats