Skip to content

About

Scan for malicious packages based on Keyv compromise

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Keyv / Cacheable IOC Scanner

A read-only scanner for indicators associated with the August 2026 Keyv and Cacheable npm supply-chain compromise.

The campaign began with keyv@6.0.0 and spread as a worm to hundreds of packages. Affected releases use an npm preinstall hook to execute setup.mjs, download a standalone Bun runtime, and launch an obfuscated second-stage payload. The malware targets developer and CI credentials and can install a gh-token-monitor dead-man switch that reacts when a stolen GitHub token is revoked.

This scanner does not install packages, execute package lifecycle scripts, or remove files.

Requirements

  • Linux or macOS
  • Bash
  • Node.js 18 or later
  • Network access to Socket's campaign CSV for the latest package list

The scanner has no npm dependencies.

Usage

Run a broad scan using the default locations:

./scan.sh

The default scan covers the current directory, the user's home directory, npm and pnpm caches, /tmp, /opt, /usr/local, and /etc. Nested roots are deduplicated.

Scan one or more specific locations:

./scan.sh --root /path/to/project
./scan.sh --root /path/to/project --root /path/to/another/project

Use only the built-in baseline of independently confirmed Keyv and Cacheable releases:

./scan.sh --offline

Use a locally saved Socket-format campaign CSV:

./scan.sh --packages-csv packages.csv

Skip the running-process check:

./scan.sh --no-process-scan

Display all options:

./scan.sh --help

What it checks

Compromised package versions

The scanner checks exact package name/version pairs in:

  • Installed package.json files
  • Direct dependencies pinned to exact versions
  • package-lock.json
  • npm-shrinkwrap.json
  • pnpm-lock.yaml
  • yarn.lock
  • bun.lock and bun.lockb

By default, it downloads Socket's current campaign CSV at scan time. If the download fails, it continues with a built-in baseline of 11 independently confirmed releases and exits with status 2 rather than reporting a complete clean result.

Malicious package behavior

The scanner detects:

  • The campaign's preinstall: node setup.mjs lifecycle hook
  • Known malicious SHA-256 hashes for both setup.mjs loader variants
  • The known SHA-256 hash for Math_Symbol.js and math_init.js
  • Loader strings referencing Bun 1.3.13 and the second-stage payload
  • Stage-two files matching the observed 727,680-byte payload size
  • bun-dl-* temporary runtime directories

Repository execution hooks

The scanner checks for the additional execution paths planted in compromised repositories:

  • Claude Code SessionStart hooks invoking .vscode/setup.mjs
  • VS Code folderOpen tasks invoking .claude/setup.mjs
  • Git hooks containing campaign-specific indicators
  • GitHub Actions workflows that export all repository secrets with toJSON(secrets)

Persistence and active processes

The scanner checks for:

  • gh-token-monitor.sh
  • gh-token-monitor.service
  • com.user.gh-token-monitor.plist
  • ~/.config/gh-token-monitor/
  • Running processes containing known payload or persistence names

Exit status

Status Meaning
0 No known indicators were found, and the requested package intelligence loaded successfully.
1 One or more suspicious or malicious indicators were found.
2 The scan could not load the current package list or could not start reliably.

A clean result means the scanner did not find the indicators it knows about. It does not prove that the system was never compromised.

If indicators are found

Do not rotate GitHub credentials before checking for and disabling gh-token-monitor persistence. Token revocation is the monitor's trigger and can execute an attacker-supplied handler.

Recommended response order:

  1. Isolate the affected workstation or CI runner from normal network access.
  2. Preserve relevant files, process information, npm logs, CI output, and filesystem timestamps.
  3. Find and disable gh-token-monitor services, LaunchAgents, scripts, and state files.
  4. Rebuild the affected environment when practical.
  5. Rotate credentials from a known-clean system, including GitHub, npm, cloud, CI, Vault, Kubernetes, database, and private-key material.
  6. Audit npm publications, GitHub repositories and workflows, cloud activity, and source-control access.
  7. Purge compromised releases from private registries, dependency caches, lockfiles, and installed dependency trees.

Coordinate destructive cleanup with an incident-response team when forensic evidence may be required.

Testing

Run the dependency-free contract tests:

./test_scan.sh

The tests cover clean scans, compromised package and loader detection, Yarn scoped-package detection, repository hooks, and incomplete package-intelligence handling.

For shell and JavaScript linting when the tools are installed:

shellcheck scan.sh test_scan.sh
oxlint scan.mjs

Limitations

  • This is an IOC scanner, not a complete forensic or endpoint-detection tool.
  • The campaign is active, so package intelligence can change after a scan.
  • Exact package matches show exposure but do not prove the malicious lifecycle script executed.
  • IDE configuration files may require workspace trust or user approval before executing.
  • Permission errors can prevent some directories from being inspected; the scan summary reports their count.
  • npm cache archives are not unpacked or executed during scanning.
  • Network indicators alone are not treated as proof because the loader abuses legitimate GitHub-hosted Bun releases and the payload can resolve changing destinations.

Sources

About

Scan for malicious packages based on Keyv compromise

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages