Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
npm-incident-response — Scanner for the keyv/cacheable supply-chain attack: detects compromised npm packages, verifies payload hashes, and finds persistence implants in repo and host modes. | Kitploit
Tools/GitHubGitHub/securest8/npm-incident-response
Vulnerability ScannersPersistence MechanismsMalware AnalysisDigital ForensicsSupply Chain SecurityIncident Response
GitHubsecurest8/npm-incident-response

npm-incident-response

Scanner for the keyv/cacheable supply-chain attack: detects compromised npm packages, verifies payload hashes, and finds persistence implants in repo and host modes.

View Repository
21191 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

npm-incident-response

English | Português

Standalone scanner for the keyv/cacheable supply-chain incident ("Shai-Hulud: Here We Go Again", Aug 4 2026) — 440+ npm packages compromised by a self-propagating worm that steals cloud/CI credentials and plants persistence with a dead-man's switch.

Detects, in minutes and without installing anything:

  • Compromised packages in package-lock.json, npm-shrinkwrap.json, yarn.lock (v1 and Berry), pnpm-lock.yaml and bun.lock — including transitive dependencies, with the full chain (e.g. eslint → file-entry-cache → flat-cache → [email protected]);
  • Installed payloads in node_modules (name + SHA-256 hash of the known artifacts);
  • Variants not yet on the IOC lists (heuristic: suspicious lifecycle scripts, files with the worm's names) — always marked SUSPECT, never confirmed without a hash;
  • Host persistence implants: LaunchAgent (macOS), systemd user service + linger (Linux), hooks in .claude/settings.json and .vscode/tasks.json, temporary artifacts (bun-dl-*);
  • The dead-man's switch: the implant monitors a GitHub token and runs a remote command when revocation returns 4xx. Rotating credentials before cleaning the host triggers the trap — the report warns you, and the response order below avoids the mistake.

Understand the attack

  1. The maintainer account for the keyv/cacheable families was compromised; the attacker published new versions with a "preinstall": "node setup.mjs" hook — code that runs before the package is installed, with the privileges of whoever ran npm install.
  2. setup.mjs downloads the Bun runtime from GitHub and runs the payload in it — evasion against tools that only monitor node processes.
  3. Math_Symbol.js (~728 KB, obfuscated) steals credentials: AWS instance metadata, AWS/GCP/Azure keys, Vault tokens, Kubernetes service accounts, GitHub Actions secrets, npm tokens, plus a generic regex sweep for private keys and bearer tokens on disk.
  4. It is a worm: with the stolen npm token, it injects the same hook into other packages that identity can publish, recomputes the integrity hashes and republishes. That is how it went from ~10 to hundreds of packages.
  5. It exfiltrates without a fixed C2 (GitHub repos created on the fly, DNS) and leaves a trap behind — see below.

The two vectors (the second is subtler)

  • Vector A — install: anyone who ran npm install/npm ci with lifecycle scripts enabled since 2026-08-04 09:35 UTC. With --ignore-scripts, the hook did not run.
  • Vector B — clone: the source repository received autostart hooks in .claude/settings.json (SessionStart) and .vscode/tasks.json (folderOpen) that run the loader when the cloned folder is opened — no npm install, nothing installed. This includes people who cloned the repo to investigate the incident and AI coding agents that opened the directory — one of the first public cases of AI-agent hooks (.claude/) used as a supply-chain vector.

The trap (dead-man's switch)

The implant installs a "watcher" (gh-token-monitor) kept alive by a LaunchAgent (macOS) or a systemd user service + loginctl enable-linger (Linux). Every 60 seconds it validates the stolen GitHub token against the API. While the token works, nothing happens. When the response turns 4xx — i.e. the moment you revoke the token — it runs, via eval, the contents of ~/.config/gh-token-monitor/handler: an arbitrary command defined remotely by the attacker. Public analysis does not know what it contains — it could be data destruction, re-implant, ransomware, or nothing. The risk is not assessable; that is why the response order is absolute.

Three properties that change the response:

  • Isolating the network is safe: with no connectivity there is no HTTP response, so no 4xx — the trap does not fire, and exfiltration stops. Isolate first, do not power off (volatile memory is evidence).
  • It is single-shot and self-clearing after firing — the behavior becomes unexplained, with no artifact left to investigate.
  • ~24h TTL: the watcher self-destructs after a day. Absence of artifacts does not prove the machine was clean — the scanner warns about this in host mode.

Why the usual defenses generally miss it

  • "The signature was valid" — [email protected] shipped with a passing SLSA attestation. Provenance attests to build integrity, not source: the legitimate workflow compiled already-trojanized code.
  • "The code diff didn't change" — correct: the library itself was not modified. The malice is in package.json (the preinstall hook) and two new files added to the package (setup.mjs, Math_Symbol.js).
  • "We don't use keyv" — you do, indirectly: the most common chain is eslint → file-entry-cache → flat-cache → keyv. That is why the scanner shows the chain in every finding.
  • "Nobody ran npm install" — insufficient: see Vector B.

What the script in this repository is

scan.mjs has the following properties — important for anyone responding to a supply-chain incident:

  • A single file, ~880 readable lines, zero dependencies. No npm install. Audit the whole of scan.mjs in 15 minutes before running it.
  • Zero egress. No data leaves your machine. No telemetry, no "send the result for analysis". The only network operation is --update (download a fresh IOC manifest), explicit and optional.
  • Read-only. The scanner does not modify, remove, or execute anything it finds.
  • Works offline. docker run --network=none or an isolated machine: just copy scan.mjs + iocs.json.

How to use it in your company

Requirement: Node.js ≥ 18 (any machine with npm already has it). Download the two files — scan.mjs + iocs.json — and that is it: no installation.

Heads-up: if you cloned this whole repository, the fixtures/ folder contains inert IOCs used in the tests (real names and versions, dummy content — no malware). The scanner skips it automatically and warns in the output; findings from it only appear if you scan it on purpose.

There are two run modes that answer different questions, and that is what decides where to run:

  • The repo mode reads lockfiles and node_modules — and lockfiles live in git, so it can be centralized: one person scans every repository in the company.
  • The host mode looks for the implant (watcher, LaunchAgent/systemd, IDE hooks), which lives on the machine where the code executed — that is not in git and cannot be centralized.

Step 1 — AppSec scans all repositories (one person, one machine)

node scan.mjs repo /folder/with/all/the/repos --json=result.json --html=report.html

Answers "which projects are exposed" in minutes, without involving anyone. Accepts multiple paths; walks subdirectories (monorepos and workspaces included).

Step 2 — whoever worked on the affected projects scans their own machine

For each project with a finding, identify who touched it since 2026-08-04 09:35 UTC (git log, CI logs). Those people run, on their machine:

node scan.mjs        # current directory + host, in ~30 seconds

In scope: anyone who (a) ran npm install/npm ci in the window; or (b) merely cloned and opened the folder in VS Code or an AI agent — Vector B needs no install.

Since the cost is ~30 seconds and the funnel can leak (a stray clone, a personal project), the safest internal message is: every developer runs node scan.mjs once and sends the --json/--html to AppSec. Sending is manual by design — the scanner has no telemetry (zero egress).

Step 3 — CI runners and build servers

Download Tool