Popular npm Packages in the keyv and Cacheable Namespaces Compromised in Active Supply Chain Attack
An active supply chain attack compromised the maintainer account for the keyv and cacheable npm package families, injecting malicious preinstall hooks into at least 14 packages with tens of millions of weekly downloads. The two-stage payload downloads a standalone Bun runtime to execute a heavily obfuscated second stage that harvests cloud, CI, and npm credentials, self-propagates by republishing trojanized packages via stolen tokens, and exfiltrates encrypted data through GitHub repositories and DNS-resolved destinations. Persistence is maintained through .claude and .vscode autostart hooks that re-trigger the malware when repositories are cloned.
- sha25654dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668SHA-256 hash of setup.mjs (npm tarball preinstall loader) - Stage 1 loader that downloads Bun runtime and executes the second stage payload
- sha2569fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bccSHA-256 hash of Math_Symbol.js (npm tarball) and math_init.js (repository) - Stage 2 payload, ~728KB Bun bundle with credential theft, self-propagation, and exfiltration capabilities
- sha256fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1ebSHA-256 hash of setup.mjs (.claude and .vscode repository loader variant) - identical loader used in persistence hooks planted in source repositories
Detection / Hunteropenrouter
What Happened
Attackers compromised the maintainer account of several very popular npm packages (software libraries used by JavaScript developers), and injected malicious code that runs automatically when someone installs these packages. The malicious code downloads a separate runtime tool called Bun, then uses it to run a hidden second program that steals passwords and access keys for cloud services like AWS, Google Cloud, and Azure, as well as tokens for GitHub and npm. The stolen credentials are used to publish more infected packages, spreading the attack like a worm. The attackers also plant hidden startup hooks in developer tools (VS Code and Claude AI) so the malware restarts whenever a developer opens the affected project. Anyone who installed these packages on or after August 4, 2026 should treat their environment as compromised, rotate all credentials, and audit for unauthorized package publications.
Key Takeaways
- Active supply chain compromise of keyv and cacheable npm package namespaces affecting tens of millions of weekly downloads, with malicious preinstall hooks added to at least 14 packages as of August 4, 2026.
- Malware uses a two-stage loader: setup.mjs downloads a standalone Bun runtime to execute an obfuscated 728KB payload (Math_Symbol.js), potentially bypassing controls that only monitor Node.js processes.
- Payload performs broad credential theft (AWS/GCP/Azure keys, Vault tokens, K8s service account tokens, GitHub Actions OIDC, npm tokens) and self-propagates by republishing trojanized versions of other packages using stolen npm tokens and OIDC trusted publishing.
- Persistence is achieved via autostart hooks in .claude/settings.json and .vscode/tasks.json, which re-trigger the loader when developers or AI coding agents open cloned repositories without requiring npm install.
- Trojanized packages shipped with valid sigstore provenance attestations because the legitimate CI pipeline built already-trojanized source, demonstrating that provenance attests build integrity, not source integrity.
Affected Systems
- Node.js / npm ecosystems
- Developer workstations with npm or Bun installed
- CI/CD runners and build agents
- Cloud environments (AWS, GCP, Azure)
- HashiCorp Vault deployments
- Kubernetes clusters
- GitHub Actions workflows
- VS Code and Claude AI coding agent environments
Vulnerabilities (CVEs)
None identified.
Attack Chain
- Initial Access: Maintainer account (Jaredwray) compromised; attacker publishes trojanized versions of keyv, cacheable, and related npm packages with malicious preinstall hook
- Execution: npm install triggers preinstall hook running node setup.mjs, which downloads a standalone Bun runtime and uses it to execute the obfuscated second stage (Math_Symbol.js)
- Credential Theft: Payload queries AWS instance metadata service, reads credential files, Vault tokens, K8s service account tokens, npm tokens, and performs TruffleHog-style regex sweep for generic secrets on disk
- Self-Propagation: Using stolen npm tokens and OIDC trusted publishing, payload enumerates maintainer packages, downloads tarballs, injects the same preinstall hook, and republishes trojanized versions with freshly minted sigstore provenance
- Exfiltration: Stolen data encrypted with AES-256-GCM under operator-controlled public key, then committed to attacker-controlled GitHub repositories via API and sent to DNS-resolved destinations
- Persistence: Autostart hooks planted in .claude/settings.json (SessionStart) and .vscode/tasks.json (folderOpen) to re-trigger loader when repositories are cloned or opened
Detection Availability
- YARA Rules: No
- Sigma Rules: No
- Snort/Suricata Rules: No
- KQL Queries: No
- Splunk SPL Queries: No
- EQL Queries: No
- Other Detection Logic: No
- Platforms: Socket AI scanner
Socket's AI scanner flagged the malicious preinstall hook in [email protected] within six minutes of publication. No YARA, Sigma, Snort, or Suricata rules are provided in the article. The article describes behavioral detection indicators for hunting but does not include ready-to-deploy rule content.
Detection Engineering Assessment
| Dimension | Rating | Rationale |
|---|---|---|
| EDR Visibility | Medium | The use of Bun runtime instead of Node.js for second stage execution may bypass controls that only monitor Node.js processes. However, the initial node setup.mjs execution and child process spawning patterns are visible to EDR. Temporary directory creation (bun-dl-*) and file writes (Math_Symbol.js, math_init.js) are detectable. |
| Network Visibility | Medium | The malware communicates over HTTPS to GitHub and npm registry APIs, and uses DNS for resolving delivery destinations. Cloud metadata service queries (169.254.169.254) from build agents are detectable if network monitoring covers egress from CI runners. Encryption of exfiltrated data limits content inspection. |
| Detection Difficulty | Hard | The two-stage execution via Bun runtime evades Node.js-focused monitoring. Polymorphic basE91 string encoding makes static analysis difficult. Use of legitimate GitHub and npm APIs for C2 and exfiltration blends with normal developer traffic. Valid sigstore provenance on trojanized packages undermines trust-based supply chain controls. |
Required Log Sources
- Process creation and command line logging (Sysmon Event ID 1 or EDR equivalent)
- File creation and modification events (Sysmon Event ID 11)
- Network connection events (Sysmon Event ID 3)
- DNS query logs
- Cloud metadata service access logs (AWS CloudTrail, VPC Flow Logs)
- npm registry publish audit logs
- GitHub audit logs for repository creation and commit events
- CI/CD runner logs
Hunting Hypotheses
| Hypothesis | Telemetry | ATT&CK Stage | FP Risk |
|---|---|---|---|
| Consider hunting for node processes executing a file named setup.mjs that subsequently spawn a bun process, as this represents the two-stage loader chain | Process creation events with command line arguments and parent-child process relationships | Execution | Low - the specific setup.mjs to bun process chain is unusual in normal npm install workflows |
| Consider hunting for temporary directories matching the pattern bun-dl-* created during npm install operations, as the loader uses this pattern for its downloaded Bun runtime | File system creation events with path pattern matching | Execution | Low - this directory naming pattern is specific to the malware loader |
| Consider hunting for processes querying the cloud instance metadata service (T1552.005) originating from CI/CD build agents or developer workstations, especially node or bun processes | Network connection logs to 169.254.169.254 and 169.254.170.2, cloud metadata service access logs | Credential Access | Medium - some legitimate CI processes query metadata services for instance configuration |
| Consider hunting for files named Math_Symbol.js or math_init.js appearing on disk outside of expected project source directories, as these are the second stage payload filenames | File creation events with filename matching | Execution | Low - these filenames are specifically chosen by the attacker and unlikely in normal projects |
| Consider hunting for unexpected npm package publications on August 4, 2026 from maintainer accounts in the keyv, cacheable, or related namespaces, as the worm republishes trojanized versions | npm registry audit logs, webhook notifications for package publishes | Lateral Movement | Low - package publishes from compromised accounts during the known attack window are high-confidence indicators |
Control Gaps
- Node.js-only process monitoring misses second stage execution via standalone Bun runtime
- Supply chain provenance validation (sigstore) does not detect trojanized source code built by legitimate CI pipelines
- Allowlist-based package registries may not catch version bumps within already-approved package scopes
- Network egress controls may not flag HTTPS traffic to github.com and registry.npmjs.org as suspicious since these are common developer destinations
- AES-256-GCM encryption of exfiltrated data prevents DLP content inspection
Key Behavioral Indicators
- Process ancestry: node.exe or node process spawning a bun process during npm install
- File system: creation of bun-dl-* temporary directories during package installation
- File system: presence of Math_Symbol.js or math_init.js in project directories or temp paths
- File system: modifications to .claude/settings.json adding SessionStart hooks or .vscode/tasks.json adding folderOpen tasks
- Network: cloud metadata service queries (169.254.169.254) from node or bun processes on CI runners
- Registry/npm: unexpected package version publishes from known-compromised maintainer accounts
False Positive Assessment
Low - The specific indicators (setup.mjs preinstall hook, Math_Symbol.js payload, bun-dl-* temp directories, node-to-bun process chain) are highly specific to this campaign. Cloud metadata queries from CI runners carry moderate false positive risk as some legitimate processes access these endpoints.
Recommendations
Immediate Mitigation
- Verify against your organization's incident response runbook and team escalation paths before acting. Consider pinning all affected packages to the version immediately prior to the compromised versions listed in the article and rebuilding lockfiles with exact version pins and integrity hashes.
- Consider blocking the entire keyv, @keyv, and cacheable scopes in your registry proxy or allowlist rather than individual versions, as new trojanized packages are appearing in real time.
- If any affected package version was installed on a host, consider rotating and revoking all credentials reachable from that host: npm tokens, GitHub PATs and GITHUB_TOKEN, AWS/GCP/Azure keys, Vault tokens, Kubernetes service account tokens, and CI organization/repository secrets.
- Consider auditing npm accounts for unexpected package versions published on August 4, 2026, and auditing GitHub for newly created repositories and unexpected commits that may contain exfiltrated data.
- If your EDR supports host isolation, consider isolating any CI runners or developer workstations that installed affected package versions until credential rotation is complete.
Infrastructure Hardening
- Evaluate whether your CI/CD pipelines can be configured to ignore npm preinstall and postinstall lifecycle scripts by default, only enabling them for explicitly reviewed packages.
- Consider implementing network-level restrictions preventing CI runners from accessing cloud metadata services unless explicitly required, to limit credential theft via T1552.005.
- Evaluate whether your package registry proxy can enforce scope-based allowlisting rather than version-based allowlisting to prevent automatic pulls of new malicious versions within trusted scopes.
- Consider implementing additional monitoring for npm publish events from your organization's maintainer accounts, with alerts for unexpected version bumps or publishes outside normal release windows.
User Protection
- Consider deploying EDR detection rules for the node-to-bun process spawning pattern and bun-dl-* temporary directory creation pattern described in the article.
- If applicable, evaluate whether your development environment policies can restrict or monitor modifications to .claude/settings.json and .vscode/tasks.json files in cloned repositories.
- Consider scanning developer workstations for the presence of Math_Symbol.js, math_init.js, or setup.mjs files in npm cache or project directories.
Security Awareness
- Consider rolling guidance into existing developer awareness programs about the risk of npm lifecycle scripts (preinstall, postinstall) and how they execute automatically during package installation.
- If your organization uses AI coding agents (e.g., Claude), consider informing developers about the risk of malicious SessionStart hooks in .claude/settings.json files in cloned repositories.
- Consider adding supply chain attack scenarios to existing developer training, emphasizing that signed/provenanced packages can still contain malicious code if the source was compromised before building.
MITRE ATT&CK Mapping
Initial Access
Execution
Stealth
Credential Access
Command and Control
Exfiltration
Additional IOCs
- File Paths:
setup.mjs- Stage 1 loader script added to trojanized npm packages via preinstall hook; downloads Bun runtime and executes second stageMath_Symbol.js- Stage 2 payload file added to trojanized npm packages; ~728KB obfuscated Bun bundle with credential theft and self-propagation capabilitiesmath_init.js- Repository variant name for the identical Stage 2 payload used in .claude/.vscode persistence hooks.claude/settings.json- Persistence file planted in source repositories; contains SessionStart hook that executes the loader when a developer or AI agent opens the project.vscode/tasks.json- Persistence file planted in source repositories; contains folderOpen task that executes the loader when a developer opens the project in VS Code
- Command Lines:
- Purpose: Execute malicious preinstall hook during npm install | Tools:
node| Stage: Initial execution |node setup.mjs - Purpose: Execute second stage payload using downloaded standalone Bun runtime | Tools:
bun| Stage: Execution |execFileSync(<bunBinary>, [<payloadPath>])
- Purpose: Execute malicious preinstall hook during npm install | Tools:
- Other:
37f9f847e9c3e520b47d83a9029e199dbc30c6a195a1d80467d0fb1a6fd5068728ad4d1a422995ca578359263afdac5d3b4fed7a6b9befad27de19cca6966952- SHA-512 hash of keyv-6.0.0.tgz tarball containing the trojanized package with malicious preinstall hook@cacheable/[email protected]- Trojanized npm package in cacheable family published during August 4, 2026 burst@cacheable/[email protected]- Trojanized npm package in cacheable family published during August 4, 2026 burst@cacheable/[email protected]- Trojanized npm package in cacheable family published during August 4, 2026 burst@cacheable/[email protected]- Trojanized npm package in cacheable family published during August 4, 2026 burst@qlik/[email protected]- Trojanized npm package in Qlik namespace, indicating worm spread beyond initial keyv/cacheable ecosystems@qlik/[email protected]- Trojanized npm package in Qlik namespace, indicating worm spread beyond initial keyv/cacheable ecosystems@qlik/[email protected]- Trojanized npm package in Qlik namespace, indicating worm spread beyond initial keyv/cacheable ecosystems