# Popular npm Packages in the keyv and Cacheable Namespaces Compromised in Active Supply Chain Attack

> Maintainer account jaredwray was compromised to publish malicious versions of keyv (6.0.0) and 10+ packages across the keyv and cacheable ecosystems on August 4, 2026. A malicious preinstall hook (setup.mjs) downloads a standalone Bun 1.3.13 runtime to execute a second-stage credential-stealing payload (Math_Symbol.js, ~728 KB) with self-propagation via npm OIDC trusted publishing, DNS exfiltration, and AI coding agent persistence through .claude/settings.json and .vscode/tasks.json.

- **Published:** 2026-08-04T00:00:00Z
- **Last reviewed:** 2026-08-04T00:00:00Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-1860
- **ID:** TL-2026-1860
- **Severity:** CRITICAL
- **Category:** SUPPLY_CHAIN
- **Status:** ACTIVE
- **Actor:** TeamPCP
- **Detections:** 9 · **IOCs:** 32 (full data via the Threadlinqs MCP server — Purple tier)

## Description

On August 4, 2026, the npm maintainer account 'jaredwray' was compromised and used to publish malicious versions of keyv (6.0.0) and at least ten additional packages across the keyv and cacheable namespaces. These packages are extremely widely used (keyv alone ~154M weekly downloads and 1,700+ dependents) and serve as transitive dependencies of common tooling such as ESLint, meaning most victims never install them directly. The attack is a continuation of the TeamPCP 'Miasma' / 'Mini Shai-Hulud' self-propagating worm campaign first documented in March 2026, which was the first documented supply chain attack to weaponize AI coding agent configuration files as persistence vectors. The malicious keyv@6.0.0 hijacked the legitimate v6.0.0 release that the maintainer had announced for mid-to-late July 2026; the attacker force-pushed to main, deleted and recreated the v6.0.0 tag, and manipulated CI/CD pipelines in real time.

Delivery was carefully crafted: the published library code in dist/ was byte-identical to the last clean release, and all malicious behavior lived in an added preinstall hook in package.json ('preinstall': 'node setup.mjs', with files: [dist, LICENSE, setup.mjs, Math_Symbol.js]). The package behaves normally after install, but the host is already compromised by that point. Stage 1 (setup.mjs) is a lightly obfuscated Node script that detects platform and architecture (including Alpine/musl via ldd --version and /etc/os-release), downloads a standalone Bun 1.3.13 runtime from the official github.com/oven-sh/bun GitHub releases, unzips it (system unzip, or PowerShell Expand-Archive on Windows, or a pure-JS ZIP fallback parser), and executes the second stage under the freshly fetched Bun binary. Running under Bun sidesteps host Node version restrictions and Node-level monitoring.

Stage 2 (Math_Symbol.js, ~728 KB Bun bundle) protects its strings with polymorphic basE91 encoding - one shared numeric opcode table drives dozens of per-scope alphabets decoded lazily, requiring reimplementation of basE91 and brute-forcing each alphabet to recover strings. It targets cloud provider credentials (AWS instance metadata at 169.254.169.254 and 169.254.170.2, credential chains, Secrets Manager across all regions; GCP service account private keys; Azure client secrets), secrets management (HashiCorp Vault tokens from /home/runner/.vault-token and /run/secrets/VAULT_TOKEN), container orchestration (Kubernetes service account tokens from /var/run/secrets/kubernetes.io/serviceaccount/token), CI/CD (GitHub Actions OIDC request tokens, org and repo secrets), and package registry credentials (npm tokens via registry whoami and token endpoints). It also performs a TruffleHog-style regex sweep for keys, bearer tokens, and private key blocks on disk. Internal module log tags include [collector], [dispatcher], [provenance], and [publish].

The payload turns credential theft into a worm by calling registry.npmjs.org/-/whoami to identify the victim, searching the registry for other packages the compromised token can reach, minting publish credentials via the npm OIDC token exchange endpoint (registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/), and for each discovered package downloading the tarball, injecting the same preinstall hook plus payload files, recomputing integrity and shasum, bumping the version, and PUT-ing to the registry. Where npm OIDC trusted publishing is available, republished versions inherit valid provenance - as the blog notes, 'provenance attests build integrity, not source integrity.' The initial keyv@6.0.0 shipped with a passing attestation.

Exfiltration uses no fixed C2 host. Two channels are used: a GitHubSender that creates repositories via POST /user/repos and commits stolen findings using GraphQL's createCommitOnBranch mutation, and a DomainSender that exfiltrates stolen data over DNS. The source repository also plants autostart hooks that activate without npm install: .claude/settings.json (a SessionStart hook that executes the loader when an AI coding agent opens the cloned repo) and .vscode/tasks.json (a folderOpen task that executes the loader when a developer opens the repo in VS Code).

Any environment that installed an affected version and ran install scripts should be treated as fully compromised. The impact extends to developer workstations and CI runners, where the payload can exfiltrate cloud provider keys, Vault/Kubernetes tokens, GitHub/npm credentials, and any secrets matching its regex sweep. A single compromised CI token can extend the campaign to additional packages via self-propagation. The presence of @thiennq/docs-viewer (a package published by a separate account) in the compromised set suggests the OIDC-driven propagation may have spread beyond the jaredwray namespace. No CVE has been assigned yet; detection is behavioral and artifact-based.

## MITRE ATT&CK

- T1195 Supply Chain Compromise
- T1078 Valid Accounts
- T1059 Command and Scripting Interpreter
- T1204 User Execution
- T1546 Event Triggered Execution
- T1098 Account Manipulation
- T1027 Obfuscated Files or Information
- T1036 Masquerading
- T1574 Hijack Execution Flow
- T1528 Steal Application Access Token
- T1552 Unsecured Credentials
- T1082 System Information Discovery
- T1005 Data from Local System
- T1071 Application Layer Protocol

## Sources

- [Socket.dev: Popular npm Packages in the keyv and Cacheable Namespaces Compromised in Active Supply Chain Attack](https://socket.dev/blog/popular-npm-packages-in-the-keyv-and-cacheable-namespaces-compromised-in-active-supply-chain)
- [Socket.dev Analysis: keyv 6.0.0 package.json](https://socket.dev/npm/package/keyv/files/6.0.0/package.json)
- [Socket.dev Analysis: keyv 6.0.0 setup.mjs](https://socket.dev/npm/package/keyv/files/6.0.0/setup.mjs)
- [Security Joes: Shai-Hulud Miasma - When a Supply Chain Worm Learned to Hijack AI Coding Agents](https://blog.securityjoes.com/post/shai-hulud-miasma-when-a-supply-chain-worm-learned-to-hijack-ai-coding-agents)
- [Cloud Security Alliance: Research Note - Mini Shai-Hulud Supply Chain / AI Pipeline](https://labs.cloudsecurityalliance.org/research/csa-research-note-shai-hulud-supply-chain-ai-pipeline-202605/)
- [Dataminr: TeamPCP / Shai-Hulud 3.0 Intel Deep Dive](https://www.dataminr.com/resources/cyber-intel-deep-dive-teampcp-shai-hulud-3-0/)
- [Morphisec: It's In Your AI Assistant Now - Shai-Hulud Wave 3 and the Miasma Worm Targeting npm](https://www.morphisec.com/blog/its-in-your-ai-assistant-now-shai-hulud-wave-3-and-the-miasma-worm-targeting-npm/)
- [Socura: Supply Chain Worm Campaign Updates - Miasma / TeamPCP VS Code Exploit](https://socura.co.uk/threat-alerts/supply-chain-worm-campaign-updates-miasma-teampcp-vs-code-exploit)
- [CISA: Widespread Supply Chain Compromise Impacting npm Ecosystem](https://www.cisa.gov/news-events/alerts/2025/09/23/widespread-supply-chain-compromise-impacting-npm-ecosystem)
- [npm Registry: keyv package page](https://www.npmjs.com/package/keyv)
- [npm Registry: cacheable-request package page](https://www.npmjs.com/package/cacheable-request)
- [GitHub: jaredwray/cacheable monorepo](https://github.com/jaredwray/cacheable)
- [GitHub: jaredwray/keyv issue #1834 (v6.0.0 release plan)](https://github.com/jaredwray/keyv/issues/1834)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-1860
