Scan this machine for indicators of an npm/PyPI supply-chain compromise and produce a clear verdict report. Use whenever the user pastes or links a security advisory about compromised packages (Socket, Aikido, Snyk, Phylum posts, CVE writeups, "X package was hijacked" news) and wants to know if they are affected; whenever they ask "am I compromised", "check my device/laptop for that malware", "did the worm hit us", "are we exposed to the keyv/Shai-Hulud/xz-style attack"; and whenever they mention malicious package versions, credential-stealing postinstall/preinstall scripts, or ask to audit node_modules, lockfiles, or package caches against known-bad versions — even if they never use the words "scan" or "IOC".
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Scan this machine for indicators of an npm/PyPI supply-chain compromise and produce a clear verdict report. Use whenever the user pastes or links a security advisory about compromised packages (Socket, Aikido, Snyk, Phylum posts, CVE writeups, "X package was hijacked" news) and wants to know if they are affected; whenever they ask "am I compromised", "check my device/laptop for that malware", "did the worm hit us", "are we exposed to the keyv/Shai-Hulud/xz-style attack"; and whenever they mention malicious package versions, credential-stealing postinstall/preinstall scripts, or ask to audit node_modules, lockfiles, or package caches against known-bad versions — even if they never use the words "scan" or "IOC".
Supply-chain compromise sweep
Check a developer machine against the indicators of compromise (IOCs) from a supply-chain
attack advisory, then report a verdict the user can act on. The sweep is strictly
read-only: never delete, quarantine, execute, or "clean up" anything you find, and never
run package installs during the sweep — an npm install mid-investigation can cause the
very infection you're checking for.
Safety rules (read before anything else)
Never advise rotating or revoking credentials until persistence is ruled out.
Modern worms (e.g. Shai-Hulud variants) install dead-man's switches that poll the
stolen token and execute a remote-supplied handler the moment the token stops working.
Rotation is the trigger. The sweep order below exists for this reason: persistence
first, credentials last.
Do not open, node, bun, or otherwise execute suspicious files. Hash them and
report paths. Reading them with head/strings is fine.
Do not cd into or run installs in a repo that may contain a compromised lockfile.
If you find a FLAG-level hit, stop expanding scope and report immediately — the
user needs to know now, and containment decisions (network isolation, which creds are
exposed) are theirs to make.
Step 1 — Build the IOC file
Collect indicators into a JSON file in your scratchpad (e.g. iocs.json). Sources, in
order of preference:
The advisory the user pasted or linked. Extract every concrete indicator.
references/known-campaigns.md — bundled IOCs for known campaigns. Use when the
user names an attack ("the keyv thing") without pasting details.
Web search for the vendor writeup (Socket, Aikido, Snyk, Wiz, StepSecurity) when
the user's description is vague. Prefer primary vendor posts; they carry the hashes.
Schema (every field optional — the script skips empty sections):
date_window_start: the day before the earliest malicious publish, so "what did this
machine fetch during the attack window" is answerable.
payload_filenames are names unique enough that existence alone is damning.
loader_filenames are common names (setup.mjs, postinstall.js) where only a hash
match convicts — the script treats the two differently, so sort them correctly.
Defang indicators when copying (npm-cache[.]com → npm-cache.com).
Second argument is the code root; ask nothing — default to ~/dev unless the user said
where their code lives or the project directory is obviously elsewhere. Run additional
passes for other roots if the user has several (e.g. ~/work). The full-tree scans can
take a couple of minutes on large trees; use a generous Bash timeout (≥5 min).
The script prints labeled sections ending in FLAGS=<n> WARNS=<n>:
FLAG — an IOC matched. Evidence of compromise.
WARN — needs your judgment (an install hook, an unrecognized LaunchAgent, a
loader-named file with a different hash).
INFO — context confirming what was checked.
Step 3 — Judge the WARNs
This is where you earn your keep. Common false positives and how to clear them:
Loader-named files with non-matching hashes: setup.mjs exists in plenty of
legitimate packages (motion-dom ships one). Non-matching hash + plausible location
(deep in a library's dist/) + no preinstall hook pointing at it → benign.
Substring ghosts: when you run your own follow-up greps, match whole words or path
segments. bun matches "bundle", ecto matches "dir-ecto-ry". The script already
guards its own greps; keep the discipline in yours.
User's own hooks: .claude/settings.json hooks and .vscode folderOpen tasks are
a real infection vector, but most hits are the user's own automation. Read the hook
script it points at (a few lines of head) — a git-sync helper is obviously not a
malware dropper. Flag only commands that download, decode, or execute anything you
can't account for.
Old cache entries: a cached tarball of an affected package family is only
interesting if the version is compromised or it was fetched inside the attack window.
Check the cache entry's timestamp before raising alarms.
Version-range exposure: installed cacheable@2.0.0 when 2.5.1 is compromised is
not an infection — but a ^2 range in package.json means a fresh install could pull
the bad version. That's forward-looking risk; report it in its own section, never as a
compromise finding.
If a WARN survives scrutiny, escalate it honestly: show the evidence, say what would
confirm or clear it, and do that follow-up check if it's read-only.
Step 4 — Report
End with a report in this shape (adapt lengths to findings; a clean host deserves a short
report):
## Verdict: CLEAN | EXPOSED (no infection found, but at-risk) | COMPROMISED
One-paragraph bottom line first, in plain sentences.
**What was checked** — persistence/dead-man's switch, running processes, payload files
(with hash verification), installed package versions across npm/pnpm/yarn/bun layouts,
lockfiles, package-manager caches + fetches during the attack window, install hooks,
agent/IDE autostart hooks. Note anything you could NOT check (other machines, CI runners,
teammates).
**Findings** — evidence for each non-clean item: path, hash, version, timestamp.
**Forward-looking risk** — semver ranges that could pull compromised versions on the next
install, plus concrete mitigation (`--ignore-scripts`, pinning, registry blocks).
**Beyond this machine** — CI runners, teammates, and servers that ran installs during the
attack window have the same exposure; say so explicitly.
If the verdict is COMPROMISED, append the remediation order and hold the line on it:
Isolate: pause CI, consider taking the host offline. Do not rotate anything yet.
Remove persistence first: dead-man's switch files, LaunchAgents/systemd units,
repo autostart hooks, the loader/payload files. Assume monitors exist for more than
one credential type.
Only then revoke (not just rotate) every credential reachable from the host: npm,
GitHub, cloud keys, Vault, k8s tokens, CI secrets.
Audit for spread: unexpected npm publishes under the user's accounts, new GitHub
repos, unexpected commits.
Scope and honesty
The sweep covers this machine's filesystem and caches. It cannot see CI runners, remote
servers, or whether secrets already left the box before the sweep ran — a clean sweep
after exposure to a compromised install means "no artifacts found", not "nothing
happened". Say which one you mean. If the advisory is still developing ("ongoing list of
affected packages"), note that the IOC list is a snapshot and link the live source.