wormcheck scan
Check this machine and this project
Reads the persistence points above and the lockfiles in the current folder tree, then compares them against the current wave indicators and OSV's malicious-package advisories.
INFECTED means a match on a published indicator. REVIEW means something legitimate but worth a look, such as any session-start hook. It never calls a machine infected on a guess.
wormcheck update
Pull the new wave's indicators
When a new wave is published, its file paths, strings and package versions go into the feed the same day. Every indicator links to the vendor or advisory it came from, so you can check our work.
The scan header shows the rules version and date, and warns when your rules are more than 14 days old.
wormcheck harden
Tighten how your agent installs packages
Adds a Claude Code install gate: before the agent runs an npm, pnpm, yarn, bun, pip or uv install, it blocks a package version published in the last 7 days, a version on a known-compromised list, or a near-lookalike name; if the registry can't be reached it lets the install through. It also sets ignore-scripts in ~/.npmrc if you haven't, and pnpm's minimum release age.
It shows the diff and asks before writing, backs up every file it touches, and leaves your existing hooks alone. --remove takes out exactly what it added. The gate is a speed bump, not a sandbox.
wormcheck scan · seeded test machine
wormcheck 0.1.1 · rules 2026.11.15-2 (bundled, updated 2026-11-15, 0 days old) · 7 waves
scanned ~/code/my-app · 3 agent/editor configs · 0 .pth files · 1 lockfile (2 packages)
OSV: 2 packages checked against malicious-package (MAL-) advisories
INFECTED (3)
./.claude/settings.json:9
SessionStart hook matches a Mini Shai-Hulud (TeamPCP) indicator
runs: node .vscode/setup.mjs
indicator: node .vscode/setup.mjs · Mini Shai-Hulud (TeamPCP)
SessionStart hook the worm commits into a project so it runs on every Claude Code session.
source: https://www.stepsecurity.io/blog/a-mini-shai-hulud-has-appeared
source: https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem
./.vscode/tasks.json:7
task "Environment Setup" matches a Mini Shai-Hulud (TeamPCP) indicator (runs on folder open)
runs: node .claude/setup.mjs
indicator: node .claude/setup.mjs · Mini Shai-Hulud (TeamPCP)
Folder-open task ("Environment Setup") that reruns the loader whenever the folder is opened.
source: https://www.stepsecurity.io/blog/a-mini-shai-hulud-has-appeared
./package-lock.json:10
lockfile pins compromised npm package @tanstack/router-core@1.169.5
indicator: @tanstack/router-core@1.169.5 · Mini Shai-Hulud (TeamPCP)
source: https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem
REVIEW (3) legitimate mechanisms that malware also uses; not evidence of infection
./.claude/router_runtime.js
a file at a path the Mini Shai-Hulud (TeamPCP) wave used; check whether you created it
Bun payload dropped into .claude/ for persistence (TanStack wave). The name alone is not proof (no published hash or content to compare). Source: https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem
~/.claude/settings.json:10
PreToolUse hook runs a command (matcher "Bash")
runs: ~/bin/guard.sh
PreToolUse hooks run automatically before tool calls. Keep it if you added it; delete it if you do not recognise it.
~/.local/bin/gh-token-monitor.sh
a file at a path the Mini Shai-Hulud (TeamPCP) wave used; check whether you created it
gh-token-monitor script. The name alone is not proof (no published hash or content to compare). Source: https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem
Result: INFECTED. 3 known indicators matched.
What to do now (in this order)
1. Stop the spread: close editors and agent sessions on this machine. Do not run npm/pnpm/
yarn/bun install or publish from it until step 6.
2. From a different, clean device, rotate:
- npm tokens: npmjs.com > Access Tokens > delete all; re-create later with 2FA.
Check your packages for versions you did not publish.
- GitHub: revoke personal access tokens (Settings > Developer settings), OAuth apps
and SSH keys (Settings > SSH and GPG keys); sign out other sessions. Look for
repos and workflow files you did not create.
- Cloud keys: AWS access keys, GCP service-account keys, Azure secrets, and any
credential in ~/.aws, ~/.config/gcloud, ~/.azure on this machine.
- Every secret in .env files on this machine (API keys, database URLs, Stripe
keys), plus CI secrets those repos can reach.
3. Remove the persistence entries listed above: delete the hook / task / .pth line /
file at each path. Keep a copy of each first if you want to report it.
4. Remove the compromised package versions from lockfiles and node_modules; reinstall
from a clean lockfile with scripts disabled (npm ci --ignore-scripts).
5. Run `wormcheck scan` again until it reports no INFECTED findings.
6. Then run `wormcheck harden` so the next install goes through the gate.
Rotation matters more than cleanup: these worms steal credentials when they run, so
treat every credential this machine could read as already copied.
Unedited output from a test machine we infected on purpose with published indicators. Exit code 0 = clean, 1 = indicators found, 2 = error.
// what leaves your machineYour files never leave your machine. To check lockfiles, wormcheck scan sends package names and versions to OSV's public API (api.osv.dev). Run wormcheck scan --offline to skip that call and use only the rules on disk. If you run wormcheck harden, the install gate it adds sends the names of packages your agent installs to registry.npmjs.org or pypi.org to check when that version was published.