NPM LIFECYCLE SCRIPT CHECK · RUNS IN YOUR BROWSER

Did a dependency just start running code at install time?

Paste your package-lock.json and see every package that runs a preinstall, install, postinstall, or prepare script the moment npm install touches it. Add an older lockfile and this also names exactly which packages gained one since then -- the mechanism behind the ua-parser-js (2021), coa/rc (2021), and Shai-Hulud (2025) npm supply-chain attacks. npm audit checks versions against a CVE database and has nothing to say about this.

Nothing is uploaded. The text you paste is parsed in this browser and never leaves your device.

1. Paste your package-lock.json

Prefer a CLI, or want this as a CI gate?

Same logic, zero dependencies, one file — and it can read your local node_modules directly, which gets the actual script text (a browser cannot read your filesystem, and a lockfile alone only records that a script exists, not what it does):

node cli.mjs snapshot --out baseline.json          # commit this once, after review
npm ci                                             # ...time passes, dependencies update...
node cli.mjs snapshot --out current.json
node cli.mjs diff baseline.json current.json       # exit 1 only if something newly gained a script
node cli.mjs lockfile package-lock.json            # or: just list what runs a script right now
node cli.mjs diff baseline.json current.json --ignore node-sass,esbuild

Get cli.mjs — Node 18+, nothing to install. It reads only local files: no network call, ever.

Real, dated incidents that used exactly this mechanism

PackageDateScriptWhat happened

More: why npm audit doesn't catch this, and how to wire the CLI into CI. See also how this compares to Socket, an ongoing registry-aware scanning service, and why diffing package-lock.json by eye stops working once the lockfile runs past a few hundred packages.

Common questions

Why doesn't npm audit already catch this?

npm audit matches installed versions against a database of known CVEs. A newly added or modified install-time script has no CVE until someone reports it as one — by which point it has already run on every machine that installed it. This tool does not need a vulnerability database: it reports a factual difference in what a package declares it will execute.

Is this a malware scanner?

No. It reports which packages run a script at install time, and flags a small number of well-known attacker patterns in that script's text (piping a download into a shell, an obvious network call, obfuscated/encoded code) by keyword match. A flag means "read this one", not "this is malware" — a legitimate native-module build step can also match. It is not exhaustive and it is not a verdict.

Is my dependency data uploaded anywhere?

No. The browser page parses the lockfile you paste entirely in your own browser and never sends it anywhere. The CLI reads only local files — no network call, ever.

What do I paste in?

Your project's own package-lock.json (npm 7+, lockfileVersion 2 or 3) — no extra step. For the diff, an older copy of the same file (from git history, a backup, or a previous run of node cli.mjs snapshot) goes in the optional second box.