Skip to content

About

scan JavaScript and Python lockfiles to detect supply chain vulnerabilities and known exploits

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

supplyscan

Scans JavaScript and Python lockfiles for supply-chain compromises and known vulnerabilities.

CI Release Licence Go

macOS Linux MCP

Quick Start · Installation · CLI Usage · MCP Server · Data Sources

supplyscan demo


Quick Start

brew install undont/tap/supplyscan

supplyscan scan                              # scan current directory
supplyscan check lodash 4.17.20              # check an npm package
supplyscan check django 2.2.0 -e pypi        # check a PyPI package

Features

  • Supply-chain detection across npm and PyPI by aggregating IOCs from DataDog (Shai-Hulud v2 and TeamPCP / Mini Shai-Hulud), GitHub Advisory Database, and OSV.dev, matched per-ecosystem so same-named packages don't collide
  • Vulnerability scanning via the npm audit API for npm and OSV.dev for PyPI
  • Multi-format lockfile support across npm, Yarn (classic & berry), pnpm, Bun, Deno, and Python (pip, Poetry, Pipenv, uv, PDM)
  • Heuristic advisories for packages that run install scripts and for invisible or non-ASCII characters in package names or URLs
  • CLI and MCP modes in a single binary, switchable with --mcp
  • JSON output for scripting and CI use
  • Per-source caching with a configurable TTL, so each IOC source refreshes on its own schedule

Supported Lockfiles

Package Manager Lockfile
npm package-lock.json, npm-shrinkwrap.json
Yarn Classic yarn.lock (v1)
Yarn Berry yarn.lock (v2+)
pnpm pnpm-lock.yaml
Bun bun.lock
Deno deno.lock
pip requirements.txt
Poetry poetry.lock
Pipenv Pipfile.lock
uv uv.lock
PDM pdm.lock

Written in Go and shipped as a static binary, so the scanner itself can't be compromised by the package ecosystems it scans.


Installation

Homebrew

brew install undont/tap/supplyscan

Go Install

go install github.com/undont/supplyscan/cmd/supplyscan@latest

Requires Go 1.26+ and $GOPATH/bin in your PATH.

Download binary

Pre-built binaries are available from GitHub Releases:

# macOS (Apple Silicon)
curl -L https://github.com/undont/supplyscan/releases/latest/download/supplyscan-darwin-arm64 \
  -o /usr/local/bin/supplyscan && chmod +x /usr/local/bin/supplyscan

# macOS (Intel)
curl -L https://github.com/undont/supplyscan/releases/latest/download/supplyscan-darwin-amd64 \
  -o /usr/local/bin/supplyscan && chmod +x /usr/local/bin/supplyscan

# Linux (x64)
curl -L https://github.com/undont/supplyscan/releases/latest/download/supplyscan-linux-amd64 \
  -o /usr/local/bin/supplyscan && chmod +x /usr/local/bin/supplyscan
Build from source
git clone https://github.com/undont/supplyscan.git
cd supplyscan
go build -o supplyscan ./cmd/supplyscan
mv supplyscan /usr/local/bin/

CLI Usage

The CLI is the default mode; no flags required.

# Scan current directory (recursive by default, scans every file in the tree)
supplyscan scan
supplyscan .  # shorthand

# Scan a monorepo root; all sub-package lockfiles are found and audited
supplyscan scan /path/to/monorepo

# Scan only the top level, without descending into subdirectories
supplyscan scan /path/to/project --no-recursive  # --shallow is an alias

# Scan production dependencies only (exclude devDependencies)
supplyscan scan --no-dev

# Fail (exit 3) when something can't be audited — unpinned requirements or a
# manifest with no lockfile — even if no compromise is found. Useful in CI.
supplyscan scan --strict

# Check a specific package (npm by default)
supplyscan check lodash 4.17.20

# Check a PyPI package
supplyscan check django 2.2.0 --ecosystem pypi
supplyscan check django 2.2.0 -e pypi  # short form

# Refresh IOC database
supplyscan refresh
supplyscan refresh --force  # force update even if cache is fresh

# Show status
supplyscan status

# Output raw JSON (for scripting/CI)
supplyscan scan --json
supplyscan check lodash 4.17.20 --json

# Show help
supplyscan help

Exit codes

Code Meaning
0 Clean — nothing found
1 Error (bad path, etc.)
2 Findings — a supply-chain compromise or known vulnerability
3 Coverage gaps under --strict (something could not be audited; no findings)

Coverage gaps are informational by default and do not change the exit code; only --strict turns them into the distinct exit code 3, and a real finding (exit 2) always takes precedence.


MCP Server Integration

For AI agent integration (Claude Code, Cursor, etc.), supplyscan runs as an MCP server with the --mcp flag.

Claude Code

brew install undont/tap/supplyscan && \
claude mcp add mcp-supplyscan --transport stdio -s user -- supplyscan --mcp

Claude Desktop / Cursor / Other Clients

Add to your MCP config file:

{
  "mcpServers": {
    "mcp-supplyscan": {
      "command": "supplyscan",
      "args": ["--mcp"]
    }
  }
}

MCP Tools

Tool Description
supplyscan_status Scanner version, IOC database info, supported lockfiles
supplyscan_scan Scan project directory for compromises and vulnerabilities
supplyscan_check Check single package@version
supplyscan_refresh Update IOC database from upstream sources
Tool parameters

supplyscan_scan

Parameter Type Description
path string Path to the project directory
include_dev boolean Include dev dependencies (default: true)

supplyscan_check

Parameter Type Description
package string Package name
version string Package version
ecosystem string npm (default) or pypi

supplyscan_refresh

Parameter Type Description
force boolean Force refresh even if cache is fresh

Updating

# Homebrew
brew upgrade supplyscan

# Go
go install github.com/undont/supplyscan/cmd/supplyscan@latest

Use supplyscan status (CLI) or supplyscan_status (MCP) to check your current version.


Data Sources

IOC Sources (Aggregated)

Vulnerability Data

Version-range matching

IOC entries expressed as version ranges (e.g. < 1.2.3, >= 1.0.0, < 2.0.0) are evaluated for npm using semver, so a range advisory matches any affected installed version. PyPI IOC ranges are not range-evaluated — PyPI matches exact pins, enumerated version lists, and all-versions wildcards only. This is because PyPI uses PEP 440, not semver, and adding a PEP 440 parser cuts against the tool's minimal-attack-surface design for a thin slice of cases (the overwhelming majority of PyPI malware IOCs are enumerated specific versions or all-versions typosquats). PEP 440 range support is a documented fast-follow if range-form PyPI IOCs start appearing.


Licence

MIT

About

scan JavaScript and Python lockfiles to detect supply chain vulnerabilities and known exploits

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages