Threat reportSupply ChainTL-2026-1875

ChainDrop npm Supply-Chain Compromise: Self-Propagating Mini Shai-Hulud Credential-Stealing Worm Affecting 444+ Packages

criticalACTIVE

ChainDrop npm Supply-Chain Compromise (TL-2026-1875), also tracked as ChainDrop, is a critical-severity supply-chain compromise, first published 2026-08-04 and last reviewed 2026-10-05. It is attributed to TeamPCP with medium confidence, affects jaredwray / npm keyv, maps to 46 MITRE ATT&CK techniques (T1003, T1005, T1008), and is covered by 9 detection rules and 45 indicators of compromise.

Severity
CRITICALAssessed severity
CVEs
0None referenced
Techniques
46MITRE ATT&CK
Actors
1TeamPCP
Detection rules
9SPL · KQL · Sigma
IOCs
45Indicators of compromise

Key facts for TL-2026-1875

Threat ID
TL-2026-1875
Also known as
ChainDrop, Mini Shai-Hulud worm, Shai-Hulud 3.0, Keyv supply-chain compromise
Severity
CRITICAL
Status
ACTIVE
Category
SUPPLY_CHAIN
First published
Last reviewed
Attribution
TeamPCP
Attribution confidence
MEDIUM
Motivation
FINANCIAL
Target sectors
softwaredevelopment, technology, cloudcomputing, cybersecurity, devops, ecommerce, health, financialservices
Target regions
Global
Detection rules
9
Indicators of compromise
45
Updates
2026-10-05 · 4 updates · revalidated 4× · latest source

How ChainDrop npm Supply-Chain Compromise works

ChainDrop is a large-scale npm supply-chain attack affecting 444+ packages (2,212 malicious versions) across 14+ unrelated publisher organizations, delivered via a Mini Shai-Hulud self-propagating credential-stealing worm. Malicious releases execute via the npm preinstall lifecycle hook, steal credentials (npm, GitHub, AWS, Azure, GCP, Kubernetes, HashiCorp Vault, AI agent configs, cryptocurrency wallets), exfiltrate via Ethereum blockchain-resolved C2 with AES-256-GCM + RSA-OAEP encryption, and republish modified packages to propagate, including via GitHub Actions OIDC abuse for trusted-publisher publication carrying valid SLSA provenance.

On August 4, 2026 (UTC), the npm ecosystem experienced one of the most sophisticated supply-chain attacks ever recorded. Dubbed ChainDrop, the attack propagated via a Mini Shai-Hulud variant worm that poisoned 444 packages (2,212 versions) in under four hours, affecting packages with a combined 2+ billion monthly installs. The attack began with the compromise of the GitHub account of Jared Wray, maintainer of the Keyv package (153.7M weekly downloads), and rapidly spread across the jaredwray ecosystem to packages including flat-cache (149.9M), file-entry-cache (147.6M), cacheable-request, cache-manager, ecto, and then autonomously propagated to 433 additional packages across 14+ organizations including ServiceTitan, OneReach, Ornikar, Qlik, Picsart, and Deliveroo.

The initial compromise was achieved via stolen GitHub maintainer credentials, not an npm token — the attacker pushed unsigned commits directly to the main branch and triggered legitimate release workflows configured with OIDC trusted publishing. This meant that every malicious version from the jaredwray wave carried valid SLSA provenance attestation signed by GitHub Actions. The resulting provenance accurately recorded the poisoned commit hash; it could not prove the commit was authorized.

The worm delivery mechanism exploits npm's preinstall lifecycle hook. Each poisoned package includes a setup.mjs file (29,918 bytes, wave 1; 11,017 bytes, re-obfuscated wave 2) and a heavily obfuscated 727,680-byte Bun-bundled second-stage payload (Math_Symbol.js or math_init.js). When npm install runs, the preinstall hook executes setup.mjs via Node.js, which downloads the legitimate Bun v1.3.13 JavaScript runtime from the official oven-sh/bun GitHub release and uses it to detonate the second-stage worm. The worm downloads a platform-specific Bun binary (Linux x64 glibc/musl, Linux arm64, macOS x64/arm64, Windows x64/arm64) and cleans up the staging directory afterward. If Bun is already installed, the download is skipped. The second-wave dropper variant includes a hand-rolled minimal ZIP extractor with PowerShell Expand-Archive fallback on Windows.

The stage 2 payload (727,680 bytes) is a Bun-bundled CommonJS program with three obfuscation layers: a rotated 1,283-entry string table with custom charset decoder, anti-tamper Object hardening, and AES-256-GCM encrypted configuration blobs. Its startup sequence includes a Russian-locale kill switch (exits if LANG indicates a Russian locale — a classic CIS avoidance pattern), a detached self-respawn mechanism outside GitHub Actions, and anti-debug checks. It writes a camouflaged state file at $TMPDIR/tmp.dpkg_<pid>.lock disguised as a dpkg lock.

The credential harvesting subsystem targets approximately 140 filesystem paths across 19 categories. These include npm tokens (~/.npmrc, ~/.yarnrc), GitHub tokens (via gh auth token and filesystem scanning), AWS credentials (~/.aws/credentials, config, IMDSv2, ECS metadata), Azure tokens (az account get-access-token, ~/.azure/accessTokens.json), Google Cloud (~/.config/gcloud, gcloud config config-helper), Docker (~/.docker/config.json), Kubernetes (~/.kube/config, in-cluster API enumeration), SSH keys (~/.ssh/), HashiCorp Vault (token discovery, Kubernetes auth, AWS IAM auth, KV v1/v2 path walk across all mounts), Jenkins (master.key), Terraform state files, PostgreSQL and MySQL connection strings, and cryptocurrency wallet.dat files (Bitcoin, Dash, Dogecoin, Litecoin, Zcash, Electrum). The worm also performs AWS Secrets Manager ListSecrets/GetSecretValue and SSM GetParameters calls across 16 regions, and Kubernetes namespace-wide secret enumeration.

A distinctive new capability in this generation targets AI developer tools — credential stores for Claude Code (.claude/credentials.json, .claude.json), OpenAI (.openai/auth.json), Codex (.codex/auth.json), Cursor (.cursor/credentials.json), Anthropic (.anthropic/auth.json), Gemini (.gemini/.env), OpenClaw, OpenCode, Hermes, and Kiro. The worm also performs GitHub Actions Runner.Worker memory scraping via sudo python3 — dumping readable pages of /proc/<Runner.Worker PID>/mem and grepping for "isSecret":true JSON fragments to extract every secret injected into CI/CD workflows.

The worm scans discovered credentials via 19 secret format regexes covering GitHub PATs (ghp_, gho_, ghs_, JWT formats), npm tokens (npm_), AWS key/secret/session formats, GCP service account JSON, Azure keys, database connection strings, Stripe, Slack, Twilio, SSH private keys, Docker auth configs, kubeconfigs, and generic password/token key-value pairs. Each credential is validated against the service API in real-time.

C2 infrastructure employs a defensive-resilient multi-layer architecture. The primary C2 resolution uses an Ethereum smart contract at 0xE1f2395ee43e45A1556EC6438a88c31B83493103 (function selector 0x53ed5143) via eth_call, querying 75 public RPC endpoints in order to retrieve the current C2 domain list — with no hardcoded domain, the attacker rotates C2 infrastructure on-chain. Two fallback mechanisms exist: GitHub commit search with markers "thebeautifulmarchoftime" and "IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients", and creation of a public GitHub repo with description "Shai-Hulud: Here We Go Again". The observed exfiltration endpoint is npm-cache.com:443/router (healthchecked by requiring HTTP 400 or 404 to fingerprint the server).

Data exfiltration follows a multi-layer analyst-proof envelope: gzip(JSON loot) → AES-256-GCM (random per-run 32-byte key, 12-byte IV) → RSA-OAEP-SHA256 wrapping of the AES key → base64. Only the attacker's private key can decrypt. The worm also exfiltrates via GitHub staging repos (creating repos via the victim's token and committing results-<timestamp>-<counter>.json files) and via a "Run Copilot" GitHub Actions workflow that writes ${{ toJSON(secrets) }} to format-results.txt and uploads it as an artifact named format-results.

Persistence mechanisms extend beyond npm install to the developer environment. The malicious commit planted .claude/settings.json with a Claude Code SessionStart hook and .vscode/tasks.json with a folderOpen shell task, each cross-referencing each other's dropper files (.claude/setup.mjs and .vscode/setup.mjs). Opening the repository in VS Code or starting a Claude Code session triggers execution — no npm install required. A token monitor component (gh-token-monitor.sh) is installed as a systemd user service (Linux) or LaunchAgent (macOS) that polls api.github.com/user every 60 seconds for 24 hours and executes an attacker-supplied handler when the stolen token is revoked — punishing credential rotation.

The worm's self-publishing engine is fully self-contained. It discovers maintainer packages via npm API (-/v1/search?text=maintainer:<user>&size=250, -/org/<org>/package), creates automation tokens with 2FA bypass, downloads current tarballs, injects the payload, recomputes integrity values, and publishes with self-generated Sigstore/SLSA provenance bundles (Fulcio + Rekor). One stolen token can produce malicious patch releases across every package available to that publisher.

Attribution: The payload is consistent with the Mini Shai-Hulud worm, an open-source credential-stealing worm published by the threat actor TeamPCP (also tracked as UNC6780, DeadCatx3, PCPcat, ShellForce, CipherForce) in May 2026. The ChainDrop variant carries forward distinctive markers from Shai-Hulud 2.0 (November 2025 campaign): Bun-based preinstall delivery via setup.mjs, Runner.Worker memory scraping with isSecret:true grepping, npm self-republishing with stolen tokens, and GitHub-based exfiltration. New capabilities include EtherHiding on-chain C2, RSA+AES analyst-proof exfiltration envelopes, AI agent credential theft, Russian locale kill switch, and self-minted Sigstore/SLSA provenance. Wiz attributed at high confidence via a shared RSA-4096 public key with prior TeamPCP operations (Bitwarden CLI, Checkmarx KICS). However, other researchers note that hard attribution links remain unconfirmed. Google's Threat Intelligence Group tracks the group as UNC6780, assessing a single operator with some periods of operation from South Africa. The group is financially motivated, targeting developer ecosystems across npm, PyPI, RubyGems, and Packagist. Prior TeamPCP campaigns include supply chain compromises of Aqua Security Trivy, Bitwarden CLI, Checkmarx Jenkins AST Plugin, GitHub, LiteLLM, and Telnyx.

MITRE ATT&CK techniques used in TL-2026-1875

Credential Access

T1003 OS Credential Dumping; T1528 Steal Application Access Token; T1552 Unsecured Credentials; T1555 Credentials from Password Stores

Collection

T1005 Data from Local System; T1074 Data Staged; T1119 Automated Collection; T1213 Data from Information Repositories; T1560 Archive Collected Data

Command and Control

T1008 Fallback Channels; T1071 Application Layer Protocol; T1102 Web Service; T1105 Ingress Tool Transfer; T1205 Traffic Signaling; T1568 Dynamic Resolution; T1573 Encrypted Channel

Exfiltration

T1020 Automated Exfiltration; T1041 Exfiltration Over C2 Channel; T1048 Exfiltration Over Alternative Protocol; T1567 Exfiltration Over Web Service; T1567.001 Exfiltration Over Web Service

Defense Evasion

T1027 Obfuscated Files or Information; T1036 Masquerading; T1055 Process Injection; T1070 Indicator Removal; T1497 Virtualization/Sandbox Evasion; T1564 Hide Artifacts

Discovery

T1046 Network Service Discovery; T1069 Permission Groups Discovery; T1082 System Information Discovery; T1083 File and Directory Discovery; T1087 Account Discovery; T1526 Cloud Service Discovery; T1614 System Location Discovery

Execution

T1059 Command and Scripting Interpreter; T1204 User Execution

Initial Access

T1078 Valid Accounts; T1195 Supply Chain Compromise

Persistence

T1098 Account Manipulation; T1543 Create or Modify System Process; T1546 Event Triggered Execution

Impact

T1485 Data Destruction

Privilege Escalation

T1548 Abuse Elevation Control Mechanism

lateral-movement

T1550 Use Alternate Authentication Material

Resource Development

T1583 Acquire Infrastructure

resource-development

T1608 Stage Capabilities

Affected products and versions in ChainDrop npm Supply-Chain Compromise

  • jaredwray / npm — keyv
    Vulnerable versions: 6.0.0
  • jaredwray / npm — flat-cache
    Vulnerable versions: 6.1.24
  • jaredwray / npm — file-entry-cache
    Vulnerable versions: 11.1.6
  • jaredwray / npm — cacheable-request
    Vulnerable versions: 13.0.20
  • jaredwray / npm — @cacheable/utils
    Vulnerable versions: 2.5.1
  • jaredwray / npm — cache-manager
    Vulnerable versions: 7.2.10
  • jaredwray / npm — ecto
    Vulnerable versions: 5.0.1
  • npm (444 packages across 14+ orgs) — Various npm packages (second-wave propagation)
    Vulnerable versions: 2,212 malicious versions across @servicetitan (141), @onereach (78), @or-sdk (74), @ornikar (42), @qlik (28), @nebula.js (22), and others
  • OpenJS Foundation / npm — npm CLI
    Vulnerable versions: < 11.10.0
    Fixed in: 11.10.0+ with min-release-age

Remediation for ChainDrop npm Supply-Chain Compromise

Immediate actions

  • Run npm audit and identify any affected package versions (keyv@6.0.0, flat-cache@6.1.24, file-entry-cache@11.1.6, cacheable-request@13.0.20, cache-manager@7.2.10, ecto@5.0.1, and 438+ other compromised packages across 2,212 versions)
  • Rotate ALL credentials, tokens, secrets present in any compromised environment from a clean host
  • Remove gh-token-monitor persistence prior to rotating tokens (worm detects token revocation)
  • Purge npm and yarn caches on affected endpoints and build hosts
  • Review dependency trees, lockfiles, artifact repositories, and CI caches for compromised versions
  • Pin known-good package versions and use lockfiles
  • Treat every developer workstation or CI/CD runner exposed to a compromised package as fully compromised

Workarounds

  • Use npm install --ignore-scripts to prevent preinstall hook execution
  • Configure npm min-release-age to reject packages published within the last 3-7 days
  • Run npm install with --no-optional and --ignore-scripts in CI environments
  • Use npm audit with dependency allowlists (e.g., Socket, Snyk WAF rules, or StepSecurity Harden-Runner)

Longer-term hardening

  • Update npm CLI to v11.10.0+ and use min-release-age config feature to prevent automatic installation of packages published within minutes
  • Install and use npm --ignore-scripts across CI/CD pipelines to disable lifecycle hooks as a defense-in-depth measure
  • Implement egress controls on CI runners — block outbound downloads from unexpected origins
  • Adopt dependency allowlisting, integrity checks, and provenance controls
  • Deploy phishing-resistant MFA (WebAuthn/FIDO2) + branch protection for all maintainer accounts
  • Institute AI agent configuration governance — inventory and pin .claude/ and .vscode/ configurations
  • Implement Runner.Worker memory read detection — terminate jobs attempting isSecret:true scraping
  • Rebuild shared base images and golden build runners to prevent silent reinfection

Weaknesses (CWE) in ChainDrop npm Supply-Chain Compromise

CWE-494, CWE-506, CWE-829, CWE-1104, CWE-306, CWE-522, CWE-276, CWE-269, CWE-311, CWE-94

Timeline of ChainDrop npm Supply-Chain Compromise

Showing the 20 most recent tracked events.

  • 0.00436 ETH transferred from the operator wallet to a Binance deposit address.
  • C2 resolution via the smart contract rotated to a new DGA-like domain, awqhnjewqjkl.icu, first observed ~15:15 UTC — after the initial four-hour propagation wave had already ceased.
  • ~18:10 UTC — All 11 primary carrier packages (keyv, cacheable family, flat-cache, file-entry-cache, cacheable-request, cache-manager, ecto) reverted to safe versions; keyv@6.0.0 specifically reverted to 5.6.0 by ~11:15 UTC.
  • ~13:20 UTC — Worm propagation ceases, consistent with affected organizations revoking stolen npm/GitHub tokens.
  • ~10:17 UTC — Security researchers (JFrog, StepSecurity, Microsoft) raise the first public alarm and begin incident response.
  • 11:24+ UTC — Microsoft Security Blog, StepSecurity, BleepingComputer, CyberScoop, and other research/outlets publish disclosure reports. Total: 444 packages poisoned, 2,212 malicious versions published.
  • 10:39+ UTC — npm registry begins unpublishing malicious package versions; cleanup ongoing. No new malicious packages observed after the initial 4-hour wave.
  • 10:05–13:20 UTC — Worm propagates to 433 additional packages (2,201 versions) across 14+ organizations using harvested credentials: @servicetitan (141), @onereach (78), @or-sdk (74), @ornikar (42), @qlik (28), @nebula.js (22), and others.
  • 10:28:01 UTC — ecto@5.0.1 published as part of the initial worm propagation wave.
  • 10:06–10:14 UTC — 9 malicious packages published from the jaredwray/cacheable monorepo: flat-cache@6.1.24, cacheable-request@13.0.20, cacheable@2.5.1, file-entry-cache@11.1.6, @cacheable/utils@2.5.1, cache-manager@7.2.10, and others.
  • 09:38–10:05 UTC — Worm autonomously propagates: uses stolen credentials to enumerate npm maintainer packages, injects payload, and republishes modified versions across the jaredwray ecosystem.
  • 09:35:00 UTC — keyv@6.0.0 published via OIDC trusted publishing (legitimate release workflow) with valid SLSA provenance attestation — first poisoned package on npm registry.
  • 09:23:50 UTC — Commit f97eabc deletes the cover test file from the repository.
  • 09:04:30 UTC — Camouflage commit d8c850c plants .claude/settings.json (Claude Code SessionStart hook), .vscode/tasks.json (VS Code folderOpen task), .claude/setup.mjs, .vscode/setup.mjs — cross-referencing persistence triggers.
  • 09:02:37 UTC — Poisoned commit ee2681a pushed to jaredwray/keyv main branch, injecting setup.mjs (29,918B dropper), Math_Symbol.js (727,680B stage 2 worm), fake cover test, and rewritten release tooling.
  • Attacker compromises Jared Wray's GitHub account (keyv maintainer) — no long-lived npm token used, OIDC trusted publishing was the publication method.
  • Aikido Security publicly discloses the campaign under the name ChainDrop, reporting newly infected packages appearing roughly every 25 minutes at the height of the outbreak.
  • Cyber Security Agency of Singapore publishes advisory AD-2026-009 with IOCs and mitigations. The advisory's totals (868 packages, 1,381 versions) diverge from this record's existing figures (444 packages, 2,212 versions); treated as an unreconciled cross-source discrepancy, not applied as a count update.
  • Unit 42 and Elastic Security Labs publish detailed follow-up analyses of the payload obfuscation layers and the full Ethereum dead-drop C2 timeline.
  • AFP, FBI and Western Australia Police charge two men (aged 21 and 23) as alleged principal participants in TeamPCP, the group behind the Mini Shai-Hulud worm family from which ChainDrop derives. Authorities allege 500,000+ credentials were stolen from 1,000+ organizations. Public sources do not state that the charges are specific to the ChainDrop wave.

Update history for TL-2026-1875

Sources cited for ChainDrop npm Supply-Chain Compromise

Detection coverage for TL-2026-1875

As of 2026-10-05, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-1875 across Splunk SPL, Microsoft KQL and Sigma, covering 45 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
45 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