A 5-second morning safety check for the project you're about to work on. Before your first
install/update of the day, scan its dependencies for known-malicious packages, CVEs,
freshly-published (zero-hour) deps, and missing release-cooldown / digest pinning β across
npm, PyPI and Docker, in one command.
npx supply-chain-scan
- π‘οΈ Catches what
npm auditmisses β known-malicious packages (the OSVMAL-feed), not just CVEs. - π Built for a morning routine β point it at the repo you're opening; get a clear go / review verdict.
- π§© npm + PyPI + Docker in a single pass.
- π¦ Zero runtime dependencies. A supply-chain tool shouldn't be a supply-chain risk β read all of it in 5 minutes.
- π» Cross-platform (Windows / Linux / macOS), no account, no CI, no telemetry.
The 2025β26 wave of npm and PyPI supply-chain attacks (hijacked maintainers β malicious release β fast
adoption) and malicious/typosquatted Docker images all exploit the same blind spot: tools that only know about
already-reported CVEs. supply-chain-scan layers the free defenses that actually cover the gap:
| Threat | Defense in this tool |
|---|---|
| Known-malicious package (npm/PyPI/Go/Rust) | osv-scanner + the OSV MAL- feed |
| Known CVE | osv-scanner + the package manager's audit |
| A CVE that is exploited in the wild right now | CISA KEV cross-check: every finding matched against the Known Exploited Vulnerabilities catalog β a match is shown as KNOWN EXPLOITED and outranks severity |
| Malicious release of a component you deploy but never build (the LiteLLM incident, Oct 2026: a poisoned Docker/PyPI release no lockfile ever sees) | deployed-stack watch (stack.yaml): OSV.dev queried per exact pinned version, only advisories new since the last successful run reported |
| Zero-hour malicious release (not yet reported) | freshness heuristic (flag deps published < N days ago) + the release-cooldown config check |
Install-time execution of a malicious preinstall/postinstall script (the keyv/Shai-Hulud vector, Aug 2026) |
install-time protection check: flags whether Aikido Safe Chain is active β it blocks the install in real time, before this scan (or any retrospective tool) ever sees the lockfile |
| Mutable / hijackable Docker base image | digest-pinning check (@sha256:) + optional image CVE scan |
Install-time code execution outside package.json scripts (the phantom gyp trick β Shai-Hulud/Miasma, 2026) |
build-manifest scan: flags shell-command substitution in binding.gyp/Makefile/setup.py |
Obfuscated worm payload dropped as a root JS file (e.g. bun_environment.js) |
undeclared-large-JS check: oversized root .js/.ts that isn't a declared entry point |
| Repo config that auto-runs when you open the folder in an AI coding agent (the Miasma reaches Azure wave, 2026) | agent/IDE-config scan: flags on-open execution in .devcontainer, .vscode/tasks.json, .claude hooks, .mcp.json |
No single open-source CLI combined these into a one-command morning verdict across all these ecosystems β so here it is.
The June 2026 Miasma wave (which had GitHub disable 73 Microsoft Azure repos) did not require installing a
poisoned package. It planted repository config files that execute the moment a developer opens the folder in
Claude Code, Cursor, Gemini CLI or VS Code β a devcontainer.json postCreateCommand, a VS Code task set
to runOn: folderOpen, a Claude Code hook, or an .mcp.json server command. The scan flags exactly those
auto-on-open execution points (and nothing as noisy as an ordinary settings.json), so you see them before
your editor runs them.
supply-chain-scan drives Google's free osv-scanner for the
malicious/CVE layer. Install it once, globally:
| OS | Command |
|---|---|
| macOS / Linux | brew install osv-scanner |
| Windows | winget install Google.OSVScanner (or scoop install osv-scanner) |
| Any | a release binary from osv-scanner/releases, or go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest |
(If it's missing, the scan tells you the exact command for your OS and still runs the other checks.)
As an npm CLI (any editor / terminal):
npx supply-chain-scan [project-dir] # no install
npm install -g supply-chain-scan # or install globallyAs a Claude Code plugin (adds a /supply-chain-scan skill to your morning routine):
/plugin marketplace add Flo5k5/supply-chain-scan
/plugin install supply-chain-scan@flo5k5-tools
supply-chain-scan [project-dir] # defaults to the current directory
--fresh-days <N> flag deps published less than N days ago (default 3)
--max-js-mb <N> flag undeclared root JS/TS files larger than N MB (default 0.5)
--no-recursive scan only the root dir, not nested packages (recursive by default)
--depth <N> max directory depth for the recursive scan (default 5)
--no-agent-configs skip the agent/IDE auto-exec-on-open check (on by default)
--images also pull & scan Docker base images for CVEs (slow, opt-in)
--stack <file> deployed-component inventory (auto-detects stack.yaml at the root)
--no-stack skip the deployed-stack check even if an inventory exists
--no-kev skip the CISA KEV (known-exploited) cross-check
--no-state report every deployed-stack advisory every run (no delta)
--reset-state drop the per-project delta state, then re-baseline
--json machine-readable output
--no-color disable ANSI colors
-h, --help / -v, --versionExit codes (scriptable): 0 clean Β· 1 review (findings) Β· 2 setup (osv-scanner not installed).
Every CVE the scan reports is cross-checked against the CISA KEV catalog (cached 24h): a match is
shown as KNOWN EXPLOITED and outranks severity. A source that cannot be reached (KEV offline, OSV API
down) is reported under blind spots β a clean verdict then means "clean among what could be
checked", never silence. Likewise, a directory with nothing scannable in scope says so explicitly:
absence of scope is not a clean bill of health.
Lockfiles describe what a repo builds β not the pinned versions that actually run in production. Drop a
stack.yaml next to the deploy config and the daily scan asks OSV.dev for each pin, reporting only
advisories new since the last successful run (first run = baseline; state lives per project in
~/.cache/supply-chain-scan/):
# stack.yaml β deployed pins this scan must judge
components:
- name: litellm
version: "1.106.2"
ecosystem: PyPI # npm | PyPI | Go | crates.io | NuGet
- name: follow-redirects
version: "1.16.1"
ecosystem: npmβΆ deployed stack β stack.yaml vs OSV.dev
βΉ 2 pinned component(s): litellm@1.106.2, follow-redirects@1.16.1
β litellm@1.106.2 [PyPI] β no known advisories
β follow-redirects@1.15.0 [npm] β NEW GHSA-8r9p-f939-6h3c (aka CVE-2026-xxxx) [high], fixed in 1.16.1 β KNOWN EXPLOITED (CISA KEV)
(Docker images aren't OSV-queryable packages β keep them under the digest-pinning check, which the scan already runs over Dockerfiles and compose files.)
The scan walks the workspace and picks up lockfiles and Dockerfiles in nested packages β
package-lock.json/pnpm-lock.yaml/yarn.lock, requirements.txt/uv.lock/poetry.lock,
go.sum, Cargo.lock and NuGet's packages.lock.json β skipping node_modules, build output and
vendored dirs. Point it at the repo root and every package gets scanned in one pass (the header shows
+N nested lock(s)). On a very large workspace this can be slow (osv-scanner time grows with the
dependency tree) β bound it with --depth <N> or fall back to --no-recursive.
π Supply-chain scan β acme-api
/home/you/code/acme-api
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
detected: npm(pnpm) Β· Docker(1 img)
βΆ osv-scanner β known-malicious + CVE
β 3 known vulnerabilities across 1 package(s):
axios@1.6.0 (GHSA-8hc4-vh64-cxmj) [npm]
β¦and 2 more
βΆ audit β CVE advisories
β pnpm: no high/critical advisories
βΆ pinning / cooldown
β npm: no minimumReleaseAge β add to pnpm-workspace.yaml: `minimumReleaseAge: 4320` (3 days)
βΆ install-time protection β Aikido Safe Chain
βΉ not installed β this scan only judges a lockfile that already resolved; safe-chain blocks a malicious install in real time, before any preinstall/postinstall script runs
βΉ install once: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/latest/download/install-safe-chain.sh | sh
βΆ freshness β deps changed recently & published < 3d ago (zero-hour)
β left-pad@9.9.9 [npm] β published 1d ago (fresh; vet before trusting)
βΆ Docker β base image pinning
β 1/1 base image(s) NOT pinned by digest (mutable tag β can be re-pointed):
node:22-alpine (Dockerfile) β pin to image@sha256:<digest>
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β οΈ REVIEW β see the β /β lines above before installing or updating dependencies.
The cheapest, highest-leverage defense is to refuse versions published in the last few days, so a compromised release is detected and pulled before it lands in your lockfile. The scan checks for it and offers the snippet:
- pnpm β
pnpm-workspace.yaml:minimumReleaseAge: 4320(3 days; pnpm 11 defaults this on at 1 day) - uv (Python) β
pyproject.toml[tool.uv]:exclude-newer = "2026-01-01T00:00:00Z" - Docker β pin every
FROMto a digest:FROM node:22-alpine@sha256:β¦
- Release cooldown (above) β keeps brand-new, most-likely-malicious versions out long enough to be caught.
supply-chain-scan(this tool) β the morning gate: known-malicious + CVE + fresh-dep + pinning. Runs after an install has already happened, against whatever the lockfile resolved to.- (optional, free) Aikido Safe Chain β the real-time layer.
Wraps
npm/yarn/pnpm/bun/pip/poetryand blocks a malicious install before itspreinstall/postinstallscript runs, closing the one gap a retrospective scan structurally cannot: the install that never gets a chance to finish. This tool checks whether it's installed and tells you if not. - (optional, free) the Socket.dev GitHub App β behavioral detection of novel malware on every PR. This tool catches known and fresh; Socket adds the unknown-behavioral layer.
No telemetry. The only network calls are public lookups: registry.npmjs.org / pypi.org for publish dates,
and OSV.dev (via osv-scanner) for advisories. Nothing about your project is uploaded.
- Auto-download a pinned, checksum-verified osv-scanner binary (
--install-scanner). Go (β shipped in 0.2.0 (osv-scanner parses them).go.sum) and Rust (Cargo.lock)- A GitHub Action / pre-commit recipe for teams that want this in CI too.
MIT Β© Flo5k5