Mini Shai-Hulud keyv/cacheable npm Compromise (No CVE Assigned): Self-Propagating Worm Steals CI, Cloud, and Developer Credentials

Dependency tree diagram with one compromised npm package node highlighted in red, malicious code cascading through downstream connected packages, Phoenix Security branding

Executive Summary

On August 4, 2026, an attacker took over the GitHub account behind keyv and the broader cacheable family of caching libraries, then published keyv@6.0.0 carrying a malicious preinstall hook. The payload is a variant of Mini Shai-Hulud, a self-propagating npm worm that steals credentials and then uses whatever publishing tokens it finds to poison more packages. Within roughly half an hour the same payload appeared across nine unrelated organizations, and by the end of the day multiple trackers were counting well over a thousand poisoned package versions.

Operationally, this matters because of where these packages sit. keyv pulls around 127 million weekly downloads, and two of the compromised siblings, flat-cache and file-entry-cache, live underneath ESLint. Most teams never chose to depend on them. They arrived transitively through a linter almost everyone runs, which is exactly why the exposure surface is so wide. Any workstation or CI runner that installed an affected version, or that opened a clone of the poisoned repository in VS Code or Claude Code, should be treated as credential-exposed until proven otherwise.

If the payload runs, it harvests npm, GitHub, AWS, GCP, Azure, Kubernetes, HashiCorp Vault, Stripe, and Slack secrets, reads GitHub Actions runner process memory to lift OIDC publishing tokens, and exfiltrates the collected material to attacker-controlled public GitHub repositories described “Shai-Hulud: Here We Go Again.” It also plants a watcher that fires when a stolen GitHub token is revoked, which inverts the normal incident-response reflex and makes response ordering a real operational concern. There is no CVE for this incident, and provenance signatures on the poisoned releases were valid, so neither a CVE feed nor an SLSA badge would have flagged it.

https://phxintel.security/malware.html?campaign=mini-shai-hulud-keyv-cacheable-npm-compromise#mp-list-view

TL;DR for Engineering Teams

What it is: A software supply-chain compromise of the keyv/cacheable npm maintainer account that shipped a Mini Shai-Hulud credential-stealing worm. No CVE assigned. Severity is critical in practice (Aikido scores the malware 100/100).

Where it bites: npm installs of affected versions across developer machines and CI/CD runners, plus a second path that executes when the poisoned repository is opened in a trusted VS Code or Claude Code workspace. flat-cache and file-entry-cache reach most teams transitively through ESLint.

Why it spread: The worm harvests npm publishing tokens and republishes itself into other maintainers’ packages automatically. Poisoned releases shipped with valid GitHub Actions OIDC and SLSA provenance, so they passed integrity checks that rely on signing rather than source review.

Patch status: No patch, because there is no code flaw to fix. Malicious versions have largely been unpublished and npm latest tags rolled back to clean releases. Remediation is version pinning, credential rotation, and host rebuilds.

Immediate action: Pin keyv to 5.6.0 (or 6.0.0-rc.1 if you need the v6 API), remove the credential-revocation watcher before rotating anything, then rotate every token reachable from an exposed host and rebuild affected machines.

Full shai hulud campaign tracker: https://sha1-hulud-monitoring.pplx.app

Vulnerability Overview

FieldValue
Vendor / projectkeyv / cacheable (maintainer: jaredwray)
Productkeyv, cacheable, flat-cache, file-entry-cache, and related npm packages
Vulnerability typeSupply-chain account compromise to self-propagating credential-stealing worm
CWECWE-506 Embedded Malicious Code (Claude’s own classification; not assigned by the original writeups)
CVSS scoreNot assigned. Aikido rates the malware 100/100 critical.
CVENone assigned. Do not cite CVE-2026-45321, which belongs to the separate May 11 TanStack wave.
Patch availableNo (account compromise, not a code defect)
Active exploitationConfirmed

Technical Anatomy

Root Cause Analysis

The failure is trust in a maintainer credential, not a bug in the caching code. The attacker gained control of the jaredwray GitHub account, pushed the malicious files directly to main, and immediately cut a release. Because keyv releases run through a legitimate GitHub Actions trusted-publisher workflow over OIDC, the poisoned tarballs shipped to npm with genuine SLSA provenance pointing at the real release workflow and the v6.0.0 tag.

That provenance is the subtle part. SafeDep documented that the commit planting the IDE hooks even carried a green GitHub-verified badge with its author field spoofed to github-actions[bot]. GitHub signs commits created through its API and web UI with its own key while letting the caller supply the author as free text, so a write-capable credential can manufacture a “verified” bot commit. The provenance chain proved the build pipeline was legitimate. It could not prove the source entering that pipeline was safe, and it says nothing about who held the credential. This is the recurring lesson of the 2026 Shai-Hulud waves, and it is why CVE-based and signature-based controls have no detection surface here.

Exploit Path

  1. Entry point. The attacker pushes setup.mjs, Math_Symbol.js, a “preinstall”: “node setup.mjs” line, and repo-resident .claude/.vscode hook files to main, then triggers the release workflow. Poisoned versions publish to npm with valid provenance. A telltale preinstall.test.ts added alongside the payload was deleted 21 minutes later.
  1. Trigger. On npm install, the preinstall script runs node setup.mjs, an obfuscated dropper. It checks for the Bun runtime and, if absent, downloads the legitimate Bun v1.3.13 from github.com/oven-sh/bun/releases/download/bun-v1.3.13/, executes the real payload through it, then deletes the runtime. The only install-time network egress is to GitHub, so reputation-based egress monitoring stays quiet.
  1. Impact. The 727,680-byte Math_Symbol.js bundle harvests secrets from the environment, encrypts them, and exfiltrates to attacker-created public GitHub repositories described “Shai-Hulud: Here We Go Again,” with npm-cache[.]com:443/router as a fallback channel. It then uses any npm publishing token it recovered to inject itself into other packages, increment their versions, and republish, which is what turns a single compromise into a worm.

Second Execution Path (No Install Required)

The repository itself carries a trap for anyone who clones it to inspect the code. Its .claude/settings.json holds a SessionStart hook and its .vscode/tasks.json holds an Environment Setup task with runOn: folderOpen, cross-wired so each config invokes the other directory’s script. Opening the checkout in Claude Code or VS Code can run the payload. VS Code blocks automatic tasks in an untrusted workspace and prompts before allowing them, and Claude Code applies workspace trust to repository-supplied settings, so these conditions reduce the risk rather than removing it. The keyv repo carried thousands of stars, so the population of people who cloned it to read the source after disclosure is not small.

What It Steals

The payload runs a set of targeted extractors: npm tokens from ~/.npmrc (validated live against registry.npmjs.org/-/whoami), GitHub PATs, OAuth, App, and OIDC tokens (including a read of GitHub Actions runner process memory for ACTIONS_ID_TOKEN_REQUEST_TOKEN and _URL), AWS credentials via files, environment variables, IMDSv2 with an IMDSv1 fallback at 169.254.169.254, ECS metadata at 169.254.170.2, and Secrets Manager enumeration, Kubernetes service-account tokens with direct API secret reads, HashiCorp Vault tokens with full KV v1 and v2 enumeration, and Stripe and Slack tokens. A platform-aware scanner then runs roughly 200 glob patterns for .env files, private keys, SSH material, Terraform state, Docker credentials, KeePass databases, and VPN configs.

Dead-Man’s Switch

The payload installs a watcher that executes an attacker-supplied local handler the moment the stolen GitHub token is revoked. SafeDep’s guidance is explicit and worth repeating in your runbook: hunt and remove the watcher first, then rotate, because revocation is the trigger. Community scanners describe a destructive handler in related TeamPCP waves; treat that specific behavior as reported in-family rather than independently confirmed for this sample, whose string table SafeDep left partly undecoded.

Campaign Timeline

PhaseTime (Aug 4, 2026, UTC)Activity
Staging~09:02 to 09:04IDE .claude and .vscode hook files planted on main
Initial publish~09:35keyv@6.0.0 published to npm with malicious preinstall
Family staging~09:39Payload copied into all 19 @keyv/* workspace packages
Worm spread~09:35 onwardWhole-namespace bursts across nine unrelated orgs, roughly one org every 2 to 7 minutes
Partial rollback~12:10 (5:40 p.m. IST)npm latest tags restored to clean releases for several packages

One evolution is specific to this variant: Wiz observed Ethereum RPC infrastructure used as part of command and control, which had not appeared in prior waves.

Affected Versions

Confirmed maintainer-family packages (“Publisher A”). Poisoned releases have largely been unpublished and tags rolled back.

PackageMalicious versionClean or restored targetNotes
keyv6.0.05.6.0Use 6.0.0-rc.1 if you need the v6 API; its dist/ is byte-identical to 6.0.0
flat-cache6.1.246.1.23Reaches most teams transitively under ESLint
file-entry-cache11.1.6prior clean 11.xReaches most teams transitively under ESLint
cacheable-request13.0.20prior
cacheable2.5.1prior
cache-manager7.2.107.2.9
@cacheable/memory2.2.1prior
@cacheable/utils2.5.1prior
@cacheable/node-cache3.1.2prior
@cacheable/net2.1.1prior
ecto5.0.1prior

Worm-spread packages across unrelated organizations (non-exhaustive, tags moved rapidly): the full @ornikar/* set (Wiz enumerates roughly 30 versions), @qlik/embed-react 2.5.3, @qlik/embed-runtime 1.6.4, @qlik/embed-web-components 1.7.3, @qlik/runtime-module-loader 1.5.1, @nebula.js/nucleus 0.5.1, @deliveroo/reevent 1.0.1, the @or-sdk/* set, @arv-bedrock/*, @picsart/ai-sdk 3.32.2, @hubsync/web-sdk-react 6.3.7, and picasso.js / picasso-plugin-* 2.11.6.

VERIFY: The brief’s @qlik/api@2.14.2 and the “17+ @servicetitan/* packages (eslint-config, anvil-themes, table, form, log-service)” both trace primarily to Microsoft’s public post. SafeDep separately confirmed @qlik/api@2.14.2 was published by qlikossbuild; the specific @servicetitan/* sub-package names could not be corroborated against a second primary source. Treat both the @qlik/api and @qlik/embed-* sets as in scope.

Caveat that overrides the table: latest tags changed during the incident and some sibling packages stayed clean, including the published @keyv/* adapters and the keyv 5.x line. A namespace blocklist risks both missing poisoned versions and quarantining safe releases. Match exact resolved versions against your lockfiles.

Exposure Analysis

EnvironmentRisk levelReason
CI/CD runnersCriticalPayload reads runner memory and the OIDC request token; a poisoned install here can republish your own packages under your OIDC trust
Developer workstationsCriticalBoth the install path and the IDE hook path apply; cloud CLI credentials, SSH keys, .env, Vault and Kubernetes config, KeePass and VPN files are all in scope
Anyone who cloned the repo to read itHighThe folderOpen task and SessionStart hook can fire on open, subject to workspace-trust prompts
Production serversMediumLower unless they run npm install at deploy time or hold secrets reachable from a compromised build

Real-World Impact

The reach here is a transitive-dependency problem more than a direct-dependency one. keyv sees around 127 million weekly downloads, and Aikido put flat-cache and file-entry-cache at roughly 565 million and 557 million downloads per month, most of that arriving through ESLint rather than through anything a developer added on purpose. Aikido estimated combined exposure at more than two billion monthly installs across at least 868 packages and 1,381 versions, and SafeDep counted 546 public “Shai-Hulud: Here We Go Again” exfiltration repositories created on August 4 alone.

Read those numbers carefully. They count malicious artifacts and attacker dead-drops, not victim systems. The counts also diverged between vendors and moved in real time as tags rolled back, and no vendor could reproduce a complete package-by-package list. They establish campaign magnitude. They do not tell you how many machines actually installed and executed the payload, which depends entirely on the exact version resolved on each host and whether its lifecycle script ran.

Realistic attack scenarios follow directly from what the payload collects: npm account takeover leading to onward package poisoning, cloud credential theft through IMDS and Secrets Manager, full CI/CD pipeline compromise through runner memory and OIDC token theft, and secret extraction from Vault and Kubernetes namespaces.

Protect yourself with Phoenix Purple – find TRUE critical chainable vulnerabilities with exploits

Detection Guidance

Log and Host Indicators

Look for npm install, or a child process, spawning a download to github.com/oven-sh/bun, the user-agent Bun/1.3.13, and artifacts under /tmp/bun-dl-*/ or a node_modules/keyv/Math_Symbol.js file. Watch for outbound traffic to npm-cache[.]com on :443/router and to the Ethereum RPC hosts used for C2. Flag new or unexpected .claude/settings.json, .vscode/tasks.json, setup.mjs, or Math_Symbol.js / math_init.js files in repositories or node_modules, and any .vscode task labeled “Environment Setup” with runOn: folderOpen. Search your org for public GitHub repositories described “Shai-Hulud: Here We Go Again” and for the marker string IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients. A GitHub Actions workflow that dumps ${{ toJSON(secrets) }} to a build artifact is another strong signal.

Consolidated IOCs

TypeValueSource
SHA-256 (Math_Symbol.js / math_init.js)9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bccAikido
SHA-256 (setup.mjs)54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668Aikido, SafeDep
SHA-256 (setup.mjs, community-spread)fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1ebAikido
Exfil fallback domainnpm-cache[.]com (:443/router)Wiz, Aikido
ETH RPC C2eth-mainnet.nodereal[.]io, go.getblock[.]io, eth.llamarpc[.]comWiz
Domains (Wiz-only, confirm before blocking)pypi-get[.]com, js-mirror[.]comWiz
Runtime source (abused, legitimate)github.com/oven-sh/bun/releases/download/bun-v1.3.13/*SafeDep, Aikido
User-agentBun/1.3.13Wiz
Defender signature (VERIFY, single-sourced)Trojan:npm/MalBun.AMicrosoft

No SHA-1 IOCs could be verified from reachable primary sources. Wiz publishes hash and version tables in its wiz-sec-public/wiz-research-iocs repository; pull those directly if you need the SHA-1 set.

Scanner References

Aikido surfaces this as a 100/100 malware issue and supports manual rescans, and its open-source Safe Chain intercepts installs against a threat feed. SafeDep’s vet evaluates install hooks as a CI policy gate. Socket decoded the self-propagation machinery. Wiz maintains the affected-package and IOC feed. Validate any community scanner’s IOC list against a primary source before you trust it.

Verification Steps

  1. Grep lockfiles, including transitive resolutions, for each affected package and version, for example grep -rn “keyv” package-lock.json pnpm-lock.yaml yarn.lock | grep “6\.0\.0”.
  2. Find repository checkouts touched during the window with find . -path “*/.vscode/tasks.json” -newermt “2026-08-04”, and inspect .claude/ and .vscode/ for unexpected setup.mjs.
  3. Match file hashes against the SHA-256 IOCs above rather than trusting latest tags or provenance signatures.
  4. In CI, audit any pipeline run that touched these packages during the window, and check for unexpected releases of your own packages and for injected workflows dumping toJSON(secrets).

Remediation

Immediate Actions

  1. Do not install keyv@6.0.0 or any malicious version in the tables above. Pin keyv to 5.6.0, or to 6.0.0-rc.1 if you need the v6 API. Restore clean targets across the family, including flat-cache@6.1.23 and cache-manager@7.2.9.
  2. Do not open a clone of the poisoned repository in VS Code or Claude Code.
  3. Revoke the publishing credential and disable the release workflow before you clean the tree. The 09:39 staging commit means a routine release cut from main would re-ship the payload across the whole @keyv scope.
  4. Hunt and remove the token-revocation watcher first, then rotate npm, GitHub PAT and App, AWS, GCP, Azure, Vault, Kubernetes service-account, SSH, Stripe, and Slack credentials reachable from any exposed host. Rebuild affected machines, delete node_modules, and clear the npm cache. Treat any CI pipeline that ran an install in the window as credential-exposed.

Temporary Mitigations

Move to npm 12, which blocks unapproved dependency lifecycle scripts by default. Understand its limit before you rely on it: npm 12, like –ignore-scripts, stops the preinstall-hook delivery path but not runtime-code variants and not the .claude / .vscode IDE-hook path, which execute outside npm entirely. Blanket-approving scripts through approve-scripts erases the benefit. Pin exact versions rather than ranges, add install-time policy gating in CI, enforce MFA on maintainer accounts, and adopt trusted publishing with a staged, human-approved publish step so a stolen token cannot cut a silent release.

Phoenix Security Recommendations

Phoenix Security closes the gap that CVE-based and signature-based tooling leaves open in this class of attack, because there is no CVE and the signatures were valid. Phoenix matches resolved lockfile versions against the reconciled affected-version set instead of relying on namespace blocklists or provenance, correlates the result with runtime workloads and internet-exposed services through attack surface management, and prioritizes CI/CD assets and any service whose build reached these packages during the window as credential-exposed. From there it drives remediation campaigns with assigned owners and staged rotation runbooks that sequence watcher-removal before token rotation, a non-obvious step most generic playbooks get wrong.

Behavioral detection is what actually catches the next wave. Phoenix supports standing supply-chain rules that a vulnerability feed cannot express: alerting when a package adds or changes a preinstall, postinstall, or prepare script between versions, when an install-time process contacts github.com/oven-sh/bun or any non-registry host, when a published tarball diverges from its source tree, and when unexpected .claude, .vscode, or setup.mjs artifacts or “Shai-Hulud: Here We Go Again” dead-drop repositories appear under your org. The lifecycle-script delta rule alone would have caught every Shai-Hulud wave to date.

External References

  1. Wiz Research, “keyv and cacheable npm Package Hijacked in Supply Chain Attack” (Aug 4, 2026).
  2. Aikido Security, “Keyv and friends compromised in active Shai-Hulud supply chain attack” (Aug 4, 2026).
  3. SafeDep, “keyv 6.0.0 Compromised With an Install Hook and an IDE Auto-Run Hook” (Aug 4, 2026).
  4. The Hacker News, “Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks” (Aug 4, 2026).
  5. Socket Security research on the self-propagation and republish machinery (Aug 4, 2026).
  6. Semgrep documentation of the April PyTorch Lightning PyPI compromise sharing the same .claude/.vscode hooks, setup.mjs, and Bun 1.3.13 dropper.
  7. Microsoft Threat Intelligence public advisory referencing the Trojan:npm/MalBun.A Defender detection (VERIFY: single-sourced).
  8. Wiz IOC repository: github.com/wiz-sec-public/wiz-research-iocs.

The data behind this article is available in full in the Phoenix Security Supply Chain Intelligence Report

Read the Full Supply Chain Intelligence Report

Francesco is an internationally renowned public speaker, with multiple interviews in high-profile publications (eg. Forbes), and an author of numerous books and articles, who utilises his platform to evangelize the importance of Cloud security and cutting-edge technologies on a global scale.

Discuss this blog with our community on Slack

Join our AppSec Phoenix community on Slack to discuss this blog and other news with our professional security team

From our Blog

Phoenix Purple now runs deterministic SAST and SCA on a knowledge graph, adding reachability, a chainability map, and one-click assessment and remediation. Instead of four disconnected scanner reports, engineers get one ranked fix list with a clear breaking-change verdict on every item, ready to review and ship.
Francesco Cipollone
Contents
Derek

Derek Fisher

Head of product security at a global fintech

Derek Fisher – Head of product security at a global fintech. Speaker, instructor, and author in application security.

Derek is an award winning author of a children’s book series in cybersecurity as well as the author of “The Application Security Handbook.” He is a university instructor at Temple University where he teaches software development security to undergraduate and graduate students. He is a speaker on topics in the cybersecurity space and has led teams, large and small, at organizations in the healthcare and financial industries. He has built and matured information security teams as well as implemented organizational information security strategies to reduce the organizations risk.

Derek got his start in the hardware engineering space where he learned about designing circuits and building assemblies for commercial and military applications. He later pursued a computer science degree in order to advance a career in software development. This is where Derek was introduced to cybersecurity and soon caught the bug. He found a mentor to help him grow in cybersecurity and then pursued a graduate degree in the subject.

Since then Derek has worked in the product security space as an architect and leader. He has led teams to deliver more secure software in organizations from multiple industries. His focus has been to raise the security awareness of the engineering organization while maintaining a practice of secure code development, delivery, and operations.

In his role, Jeevan handles a range of tasks, from architecting security solutions to collaborating with Engineering Leadership to address security vulnerabilities at scale and embed security into the fabric of the organization.

Jeevan Singh

Jeevan Singh

Founder of Manicode Security

Jeevan Singh is the Director of Security Engineering at Rippling, with a background spanning various Engineering and Security leadership roles over the course of his career. He’s dedicated to the integration of security practices into software development, working to create a security-aware culture within organizations and imparting security best practices to the team.
In his role, Jeevan handles a range of tasks, from architecting security solutions to collaborating with Engineering Leadership to address security vulnerabilities at scale and embed security into the fabric of the organization.

James

James Berthoty

Founder of Latio Tech

James Berthoty has over ten years of experience across product and security domains. He founded Latio Tech to help companies find the right security tools for their needs without vendor bias.

christophe

Christophe Parisel

Senior Cloud Security Architect

Senior Cloud Security Architect

Chris

Chris Romeo

Co-Founder
Security Journey

Chris Romeo is a leading voice and thinker in application security, threat modeling, and security champions and the CEO of Devici and General Partner at Kerr Ventures. Chris hosts the award-winning “Application Security Podcast,” “The Security Table,” and “The Threat Modeling Podcast” and is a highly rated industry speaker and trainer, featured at the RSA Conference, the AppSec Village @ DefCon, OWASP Global AppSec, ISC2 Security Congress, InfoSec World and All Day DevOps. Chris founded Security Journey, a security education company, leading to an exit in 2022. Chris was the Chief Security Advocate at Cisco, spreading security knowledge through education and champion programs. Chris has twenty-six years of security experience, holding positions across the gamut, including application security, security engineering, incident response, and various Executive roles. Chris holds the CISSP and CSSLP certifications.

jim

Jim Manico

Founder of Manicode Security

Jim Manico is the founder of Manicode Security, where he trains software developers on secure coding and security engineering. Jim is also the founder of Brakeman Security, Inc. and an investor/advisor for Signal Sciences. He is the author of Iron-Clad Java: Building Secure Web Applications (McGraw-Hill), a frequent speaker on secure software practices, and a member of the JavaOne Rockstar speaker community. Jim is also a volunteer for and former board member of the OWASP foundation.

Join our Mailing list!

Get all the latest news, exclusive deals, and feature updates.

The IKIGAI concept
Protected By
Shield Security PRO