Listen to this Post

Introduction
On August 4, 2026, the JavaScript ecosystem witnessed one of the most devastating supply chain attacks in history. Attackers compromised the GitHub account of Jared Wray, the maintainer of keyv—a key-value storage library with approximately 127 million weekly npm downloads—and deployed CHAINDROP, a self-propagating worm that spread to over 1,684 poisoned versions across 420 package names within hours. What makes this attack particularly insidious is that the worm doesn’t just steal credentials; it uses stolen npm tokens to republish trojanized versions of other maintainers’ packages, turning a single compromised account into a loader that infected packages from organizations including Deliveroo, Ornikar, Qlik, and ServiceTitan.
Learning Objectives
- Understand the technical mechanics of the CHAINDROP worm, including its preinstall hook, Bun runtime deployment, and credential-stealing payload.
- Learn how to detect compromised packages in your dependency trees using lockfile auditing and package integrity verification.
- Master the step-by-step incident response process, including the critical order of operations to avoid triggering the malware’s “dead man’s switch.”
You Should Know
- The Attack Chain: From Compromised Account to Worm Propagation
The attack began when threat actors seized control of the `jaredwray` GitHub account. At approximately 09:00 UTC on August 4, 2026, the attacker pushed malicious commits directly to the `keyv` repository’s main branch. The first confirmed malicious release was `[email protected]` at 09:35 UTC.
The malicious `package.json` contained a single, devastating line:
"preinstall": "node setup.mjs"
This `preinstall` hook executes before the package installation completes, with the full privileges of whoever ran npm install. No further user interaction is required.
Stage 1 – The Dropper (`setup.mjs`):
The dropper performs three critical functions:
- Checks if the Bun JavaScript runtime is installed on the victim’s machine
- If not, downloads `bun v1.3.13` directly from the official GitHub releases page
- Executes the obfuscated second-stage payload (
Math_Symbol.jsormath_init.js) using Bun
Both payload filenames share the same SHA-256 hash, making the filename a reliable indicator of infection generation.
// Simplified representation of the dropper's execution
const bunPath = downloadBun('1.3.13');
execFileSync(bunPath, ['Math_Symbol.js'], {
stdio: 'inherit',
cwd: scriptDir
});
// After execution, the temporary Bun directory is deleted to cover tracks
Stage 2 – The Payload (`Math_Symbol.js` / `math_init.js`):
The 711–728 KB payload is heavily obfuscated using control-flow flattening and a Base91 string encoding scheme. It contains Dune-themed references consistent with previous Shai-Hulud campaigns.
The payload’s capabilities include:
- Credential Harvesting: Steals npm tokens (
npm_), GitHub PATs (ghp_,gho_,ghs_), AWS credentials, GCP and Azure keys, HashiCorp Vault tokens, Kubernetes service account tokens, database connection strings, Stripe/Slack/Twilio keys, and GitHub Actions runner secrets - Credential Validation: Validates each stolen token in real-time against `registry.npmjs.org/-/whoami` before exfiltration
- Exfiltration: Encrypts stolen credentials with AES-256-GCM under an operator public key and exfiltrates them to threat actor GitHub repositories and the domain `npm-cache[.]com`
– Persistence: Plants autostart hooks in `.claude/settings.json` and `.vscode/tasks.json` that execute the payload when a developer opens an infected repository in VS Code or starts a Claude Code session - Self-Propagation: Uses stolen npm tokens to republish trojanized versions of every package the compromised identity can reach, at a rate of approximately one package per second
Worm-Generated Artifacts:
- Worm-generated commits can be identified by the author name `claude` and the commit message `chore: update config`
– When a GitHub App token is stolen, the worm commits malicious hooks to up to 50 branches per accessible repository
The Provenance Problem:
Critically, `[email protected]` shipped with passing npm provenance (a signed SLSA attestation) because the legitimate release workflow built already-trojanized source code. This means signature verification alone was not sufficient to detect the compromise.
2. Scope and Scale: Mapping the Blast Radius
The attack’s reach is staggering, though reported numbers vary due to the ongoing nature of the campaign:
| Source | Count | Detail |
|–|-|–|
| SafeDep | 1,684 poisoned versions across 420 package names | Enumeration against the npm registry |
| Aikido | 868 packages across 1,381 versions | Combined total of over 2 billion monthly installs |
| Elastic Security Labs | 400+ unique packages | CHAINDROP worm tracking |
| CISA | 500+ packages | Official advisory |
| NCSC New Zealand | 500 packages | Official advisory |
The worm reached nine unrelated organizations in approximately half an hour, moving from one organization to the next every two to seven minutes. Affected organizations include:
– @ornikar (primarily ESLint, Babel, Jest, and Prettier configs—landing on CI runners and developer laptops as dev dependencies)
– @deliveroo
– @onereach
– @qlik
– @servicetitan
– @arv-bedrock
Authentication libraries were among the poisoned packages, including @or-sdk/auth, @or-sdk/api-tokens, @or-sdk/permissions, and @arv-bedrock/auth. A credential-reading payload inside an authentication package compounds downstream exposure significantly.
The Dependency Tree Problem:
These compromised packages sit deep inside dependency trees that most teams never audit. A common chain is eslint → file-entry-cache → flat-cache → keyv, meaning most affected users never install any of these packages directly.
3. Detection: How to Know If You’re Compromised
Step 1: Audit Your Lockfiles
Search your package-lock.json, yarn.lock, or `pnpm-lock.yaml` for the confirmed malicious versions:
For npm lockfiles grep -E '"keyv": "6.0.0"' package-lock.json grep -E '"cacheable-request": "13.0.20"' package-lock.json grep -E '"cache-manager": "7.2.10"' package-lock.json grep -E '"@cacheable/utils": "2.5.1"' package-lock.json grep -E '"flat-cache": "6.1.24"' package-lock.json Broader search for any keyv/cacheable package published on or after August 4, 2026 grep -E '"(keyv|cacheable|flat-cache|file-entry-cache|cache-manager|@cacheable/)' package-lock.json
Confirmed Malicious Versions:
– `[email protected]`
– `[email protected]`
– `[email protected]`
– `@cacheable/[email protected]`
– `[email protected]`
Confirmed Affected (No Malicious Version Published Yet) :
– `file-entry-cache` (any version published on/after August 4, 2026)
– `cacheable` (any version published on/after August 4, 2026)
– `@cacheable/memory` (any version published on/after August 4, 2026)
– `@cacheable/node-cache` (any version published on/after August 4, 2026)
Clean Versions Restored as `latest`:
– `[email protected]`
– `[email protected]`
– `[email protected]`
– `[email protected]`
Step 2: Check for Malicious Files
Search for the malicious dropper and payload in node_modules
find node_modules -1ame "setup.mjs" -exec grep -l "bun" {} \;
find node_modules -1ame "Math_Symbol.js" -exec ls -la {} \;
find node_modules -1ame "math_init.js" -exec ls -la {} \;
Check package.json for the malicious preinstall hook
find node_modules -1ame "package.json" -exec grep -l '"preinstall": "node setup.mjs"' {} \;
Step 3: Check for Claude Code and VS Code Hooks
Search for persistence hooks that execute when opening repositories
find . -path "/.claude/settings.json" -exec cat {} \;
find . -path "/.vscode/tasks.json" -exec cat {} \;
Important Note: The `latest` tag is not a reliable indicator of safety. Many affected names still resolve to poisoned versions in the `latest` tag. Always check the exact resolved version in your lockfile.
4. Incident Response: The Critical Order of Operations
⚠️ WARNING: DO NOT ROTATE CREDENTIALS FIRST
The malware installs a token-revocation watcher—a “dead man’s switch” that executes an attacker-supplied command the moment a stolen GitHub token is revoked. Rotating credentials first triggers the watcher.
Step 1: Disable Install Scripts Immediately
For npm - disable all lifecycle scripts npm install --ignore-scripts For CI/CD pipelines - add this flag to all npm install commands npm ci --ignore-scripts For yarn yarn install --ignore-scripts For pnpm pnpm install --ignore-scripts
Step 2: Hunt the Watcher Before Rotation
SafeDep advises responders to locate and remove the credential-revocation watcher before rotating any exposed tokens or keys. The watcher is installed by the payload and triggers on token revocation.
Step 3: Isolate and Investigate
Check for any outbound connections to known malicious domains grep -r "npm-cache.com" node_modules/ grep -r "npm-cache.com" ./ Check for unexpected GitHub repositories in git config git config --list | grep -E "(url|remote)" Audit running processes for Bun ps aux | grep bun
Step 4: Rotate Credentials (After Watcher Removal)
Once the watcher is removed, rotate every credential that touched a build environment in the affected window:
– npm tokens (especially those used in CI)
– GitHub Personal Access Tokens and workflow tokens
– AWS credentials (including IAM keys, SSM parameters, and Secrets Manager secrets)
– GCP and Azure service account keys
– HashiCorp Vault tokens
– Kubernetes service account tokens
– Database connection strings
– Any private keys stored in the environment
Step 5: Rebuild from Clean Lockfiles
Remove node_modules and lockfile rm -rf node_modules package-lock.json Reinstall with clean versions (npm has restored clean versions as latest for key packages) npm install Or pin to known clean versions npm install [email protected] [email protected] [email protected] [email protected]
Step 6: Implement Preventive Controls
- Upgrade to npm v12: npm 12 blocks unapproved dependency lifecycle scripts by default
- Use `–ignore-scripts` in CI: Make this the default for all CI/CD pipelines
- Implement package integrity verification: Use tools like Socket.dev that flagged `[email protected]` within six minutes of publication
- Audit dependency trees regularly: Don’t rely on direct dependencies; audit transitive dependencies
- The Trust Model Problem: Why This Keeps Happening
The keyv attack exposes a fundamental flaw in the open-source ecosystem’s trust model. A single maintainer account—compromised through means that remain unclear—had the authority to publish malicious code that reached over 2 billion monthly installs.
What Makes This Attack Different:
- Valid Provenance: The malicious releases carried passing npm provenance signatures because they were built through legitimate GitHub Actions workflows
- IDE Persistence: The worm doesn’t just infect during installation; it persists through `.claude` and `.vscode` hooks that execute when developers open repositories
- Self-Propagation: This isn’t a single compromised package; it’s a worm that actively spreads using stolen credentials
- Dead Man’s Switch: The revocation watcher inverts the standard incident response workflow
The Broader Implication: The npm ecosystem’s trust model—where one maintainer’s credentials can compromise billions of installs—is the actual attack surface. Running `npm update` does not fix this problem.
Recommendations for Organizations:
- Implement a software bill of materials (SBOM) for all projects
- Use dependency scanning tools that detect malicious patterns, not just known vulnerabilities
3. Consider private registries with curated, vetted packages
4. Enforce least-privilege publishing with granular access controls
- Implement runtime protection that can detect and block malicious preinstall hooks
What Undercode Say:
- The npm trust model is fundamentally broken. A single compromised maintainer account can poison billions of monthly installs. The industry needs to move toward distributed trust models with mandatory multi-party approval for releases.
- Signature verification alone is insufficient. The keyv attack proved that valid provenance signatures can be attached to malware when the build pipeline itself is compromised. We need runtime behavioral analysis, not just static signature checks.
- The dead man’s switch changes incident response. Traditional “rotate first” thinking is dangerous. Security teams must now consider that revoking credentials can trigger attacker-controlled code execution.
- Developer workstations are now in the blast radius. The Claude Code and VS Code hooks mean that developers who merely open a compromised repository—without ever running
npm install—can be infected. This dramatically expands the attack surface. - The worm’s propagation speed is unprecedented. Moving from one organization to another every two to seven minutes, republishing entire namespaces at one package per second—this is automated, aggressive, and designed to outrun human response.
- Authentication libraries being poisoned is catastrophic. When an auth library is compromised, every application that uses it inherits the compromise, and credential-stealing code inside an auth package has privileged access to the most sensitive data.
- Dev dependencies are a primary vector. The @ornikar leg of the attack targeted ESLint, Babel, and Jest configs—tools that run on developer laptops and CI runners, not production—meaning the malware spreads through the development pipeline before reaching production.
- The Shai-Hulud family is evolving. This is the sixth known Shai-Hulud campaign, and each iteration becomes more sophisticated. The use of Ethereum smart contracts for C2 infrastructure adds a layer of resilience that traditional takedown efforts cannot address.
- Organizations need to treat every CI secret as exposed. If your CI pipeline ran during the affected window, assume all credentials are compromised and rotate them following the proper order of operations.
- This is not an npm-specific problem. The trust model issues that enabled this attack exist across every package registry—PyPI, RubyGems, Maven, and others. The JavaScript ecosystem is simply the largest and most visible target.
Prediction:
- -1 More maintainer account compromises are inevitable. Until the industry implements mandatory hardware-based authentication and multi-party approval for package publishing, threat actors will continue targeting high-value maintainer accounts. The return on investment for compromising a single account is simply too high.
-
-1 The dead man’s switch technique will be adopted by other malware families. The keyv attack demonstrated that inverting the incident response workflow is an effective defensive countermeasure. Expect future supply chain attacks to include similar revocation watchers.
-
+1 The npm ecosystem will accelerate adoption of runtime protection. Tools like Socket.dev that flagged keyv within six minutes represent the future of supply chain security. Behavioral analysis at install time will become standard practice.
-
-1 AI-assisted package development will be weaponized. The worm’s use of Claude Code hooks and the `claude` author name suggests attackers are already integrating AI tooling into their attack chains. As AI coding assistants become more prevalent, they will become attack vectors.
-
+1 Organizations will shift toward private, curated registries. The inability to trust public registries will drive enterprises to maintain private mirrors with rigorous vetting processes, similar to how Chainguard protected its customers from this attack.
-
-1 Open-source maintainers will face increased burnout and attrition. The pressure of being a single point of failure for billions of installs, combined with the personal risk of account compromise, will drive maintainers away from critical infrastructure projects.
-
+1 The incident will accelerate SLSA and sigstore adoption. While provenance wasn’t sufficient to stop this attack, the broader push toward supply chain integrity will continue, with additional layers of verification being added to the framework.
-
-1 Legal and regulatory consequences are coming. With over 2 billion monthly installs affected and authentication libraries compromised, class-action lawsuits and regulatory actions are likely, particularly in jurisdictions with strict data protection laws.
-
+1 The community will develop better incident response playbooks. The keyv attack has provided a real-world stress test of supply chain incident response. The lessons learned—particularly the order of operations issue—will improve preparedness for future attacks.
-
-1 The fragmentation of the npm ecosystem will increase. As organizations lose trust in the public registry, we may see a bifurcation between “enterprise-grade” curated packages and the public registry, potentially slowing innovation in the open-source ecosystem.
▶️ Related Video (80% Match):
https://www.youtube.com/watch?v=1E_2RlmY61M
🎯Let’s Practice For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
IT/Security Reporter URL:
Reported By: Robert Moniz – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


