npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

supply-chain-inspector

v1.5.3

Published

Standalone, zero-dependency CLI for npm supply chain security analysis — vulnerability scanning, OpenSSF Scorecard, install-script detection, publisher history, and more.

Readme

🛡️ Supply Chain Inspector

A standalone, zero-dependency Node.js script for supply chain security analysis of npm dependencies. Queries public security APIs for every package and delivers a formatted terminal report and a shareable standalone HTML report — with no install step required.

Summary table — packages, versions, vulnerability badges, scorecard bars

Collapsible findings detail — scorecard checks, version history, package info


Features

  • Vulnerability scanning via OSV.dev — known CVEs and security advisories, severity-ranked (Critical / High / Medium / Low)
  • CISA KEV cross-reference — automatically checks every discovered CVE against the CISA Known Exploited Vulnerabilities catalog, highlighting packages with actively exploited vulnerabilities in a dedicated alert section (CLI and HTML), with vendor, product, due date, required action, and ransomware campaign flag
  • Project health scoring via OpenSSF Scorecard — 10+ automated checks covering code review, branch protection, signed releases, and more
  • Install-script detection — flags packages that run preinstall, postinstall, prepare, and other lifecycle hooks (a common malware vector)
  • Publisher history — tracks who published each version to spot account takeovers
  • Version history — configurable look-back window for detecting dormancy, publish bursts, or suspicious major jumps
  • Transitive dependency support — optionally scan every resolved package in package-lock.json, not just direct dependencies
  • Lockfile-aware — auto-detects package-lock.json for exact pinned versions instead of resolving from semver ranges
  • File cache — API responses are cached to disk (npm: 6 h, OSV: 6 h, Scorecard: 24 h, CISA KEV: 24 h) so repeated runs are fast and network-friendly
  • In-flight deduplication — concurrent workers that request the same package or repo share one HTTP request instead of firing duplicates
  • Zero dependencies — uses Node.js 18+ built-in fetch; nothing to install

Requirements

  • Node.js 18 or later (uses native fetch)
  • No npm install required — the script is fully self-contained, or use npx to run it directly from the registry

Quick Start

# Run directly via npx — no install needed
npx supply-chain-inspector path/to/package.json

# Or use a URL to a remote package.json
npx supply-chain-inspector https://raw.githubusercontent.com/angular/angular/refs/heads/main/package.json

# Or install globally once to get the short "nsci" alias
npm install -g supply-chain-inspector
nsci path/to/package.json

# Or clone/copy the script and run it locally
node inspect-dependencies.js path/to/package.json

Typical output:

Supply Chain Inspector
Package: my-app 1.0.0
Source:  /home/user/my-app/package.json
Lockfile: /home/user/my-app/package-lock.json (312 resolved versions)
Cache:    /home/user/my-app/.cache

Inspecting 14 package(s) — concurrency: 5

  → express  (^4.18.2)
  → lodash   (^4.17.21)
  ...

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  SUPPLY CHAIN REPORT  ·  [email protected]  ·  14 package(s)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  PACKAGE           VERSION     VULNS          SCORECARD        SCRIPTS
  ─────────────────────────────────────────────────────────────────────────────
  express           4.18.3      0              ████████░░ 7.8   ─
  lodash            4.17.21     1 high         ██████░░░░ 5.2   ─
  ...

Usage

# Via npx (no install required)
npx supply-chain-inspector <path/to/package.json|url> [options]

# Via short alias (requires: npm install -g supply-chain-inspector)
nsci <path/to/package.json|url> [options]

# Or if running the script directly
node inspect-dependencies.js <path/to/package.json|url> [options]

Input can be:

  • Local file path: package.json or path/to/package.json
  • Remote URL: https://raw.githubusercontent.com/user/repo/refs/heads/main/package.json

Note: When using a remote URL, the lockfile (package-lock.json) is automatically fetched from the same directory. You can also explicitly specify a lockfile URL using --lockfile=<url>.


Options

Dependency Scope

By default only dependencies (production) are scanned.

| Flag | Description | |---|---| | --include-dev | Also inspect devDependencies | | --include-peer | Also inspect peerDependencies | | --include-optional | Also inspect optionalDependencies | | --include-transitive | Also inspect every transitive package resolved in package-lock.json, deduplicated by name@version. Packages already present as direct deps are skipped. Requires a lockfile. |

Version History

--version-history=<N>    Versions to keep per package (default: 10, min: 2)

| Value | What it enables | |---|---| | 2 | Downgrade / major-jump detection only | | 5 | + Rapid publish burst + dormancy detection | | 10 | + Cadence baseline (recommended) | | 20+ | Broader history, larger JSON output |

Data Collection

| Flag | Description | |---|---| | --concurrency=<N> | Max parallel package fetches (default: 5) | | --lockfile=<path\|url> | Path or URL to package-lock.json (auto-detected next to package.json if omitted; for remote URLs, auto-detects package-lock.json in same directory) | | --no-scorecard | Skip OpenSSF Scorecard lookups (faster, useful offline) | | --no-vulns | Skip OSV.dev vulnerability lookups | | --no-kev | Skip the CISA KEV cross-reference (also skipped automatically when --no-vulns is set, since there are no CVEs to match) |

Cache

| Flag | Description | |---|---| | --cache-dir=<path> | Directory for cached API responses (default: .cache/ next to the script) | | --no-cache | Disable file cache; always fetch live data |

Cache TTLs are fixed and not configurable. Delete cache files manually to force an early refresh:

| Source | TTL | Rationale | |---|---|---| | npm Registry | 6 h | Refreshed when new versions are published | | OSV.dev | 6 h | Vulnerability data is stable within hours | | OpenSSF Scorecard | 24 h | Scores are recomputed weekly by OpenSSF | | CISA KEV | 24 h | Catalog is updated weekly; daily refresh is sufficient |

Report

| Flag | Description | |---|---| | --findings | Show per-package findings detail below the summary table. By default only the table is shown; a one-line hint indicates how many packages have signals. | | --fail-on=<level> | Exit with code 1 if vulnerabilities at or above the specified severity are found. Valid levels: low, medium, high, critical (default: critical). When set to low, any vulnerability will cause a failure. When set to critical, only critical vulnerabilities trigger a failure. | | --fail-licenses=<licenses> | Exit with code 1 if any dependency uses a restricted (copyleft) license. Accepts a comma-separated list: GPL,AGPL,LGPL. Normalizes automatically: GPL-3.0-or-laterGPL-3.0GPL. Works independently of --fail-on. | | --no-kev | Skip the CISA KEV cross-reference entirely. Without this flag, any KEV match always causes exit code 1, regardless of --fail-on level — see KEV Alert. |

Output

| Flag | Description | |---|---| | --json | Print the full result array as JSON to stdout | | --output=<path> | Write JSON to a file (implies --json) | | --html=<path> | Write a fully standalone HTML security report to a file (no server or internet connection required to view) |

Color

Set NO_COLOR=1 in the environment to disable ANSI colors. Colors are also automatically disabled when stderr is not a TTY (e.g. piped output).


Output Modes

The formatted report always goes to stderr. stdout is reserved exclusively for JSON so you can pipe cleanly.

# Report only — clean terminal view, no JSON noise
node inspect-dependencies.js package.json

# Report on stderr + JSON on stdout — pipe JSON to another tool
node inspect-dependencies.js package.json --json

# Report on stderr + JSON saved to a file — review both independently
node inspect-dependencies.js package.json --output=results.json

# Write a standalone HTML report — open report.html in any browser
node inspect-dependencies.js package.json --html=report.html

# HTML report + JSON side by side (useful for both humans and tooling)
node inspect-dependencies.js package.json --html=report.html --output=results.json

# Suppress the report, get only JSON (useful for scripting)
node inspect-dependencies.js package.json --json 2>/dev/null

# Pipe JSON straight into an AI tool
node inspect-dependencies.js package.json --json | llm "analyze these deps"

Common Recipes

# Scan all dependency groups, save JSON for later AI analysis
node inspect-dependencies.js package.json \
  --include-dev --include-peer \
  --output=scan.json

# Generate an HTML report for easy sharing with your team
node inspect-dependencies.js package.json --html=report.html

# Inspect a remote package.json from GitHub (auto-detects remote lockfile)
node inspect-dependencies.js https://raw.githubusercontent.com/angular/angular/refs/heads/main/package.json

# Inspect remote package.json with full scan and HTML report
node inspect-dependencies.js https://raw.githubusercontent.com/user/repo/main/package.json \
  --include-dev --html=report.html

# Inspect remote package.json with explicit remote lockfile URL
node inspect-dependencies.js https://raw.githubusercontent.com/user/repo/main/package.json \
  --lockfile=https://raw.githubusercontent.com/user/repo/main/package-lock.json

# Inspect remote package.json with transitive dependencies (requires lockfile)
node inspect-dependencies.js https://raw.githubusercontent.com/user/repo/main/package.json \
  --include-transitive --findings

# Full scan with HTML report, JSON data, and findings detail
node inspect-dependencies.js package.json \
  --include-dev --include-peer \
  --output=scan.json --html=report.html --findings

# Full deep scan — all groups, all transitive deps, with findings detail
node inspect-dependencies.js package.json \
  --include-dev --include-peer --include-optional --include-transitive \
  --findings

# Quick scan — skip Scorecard (no outbound calls to api.scorecard.dev)
node inspect-dependencies.js package.json --no-scorecard

# High concurrency for large lockfiles (mind API rate limits)
node inspect-dependencies.js package.json --concurrency=10

# CI-friendly: plain text, no color, output to log file
NO_COLOR=1 node inspect-dependencies.js package.json 2>&1 | tee security-report.txt

# Fail the build if any critical vulnerabilities are found (default behavior)
node inspect-dependencies.js package.json --fail-on=critical

# Fail the build on high or critical vulnerabilities
node inspect-dependencies.js package.json --fail-on=high

# Fail the build on any vulnerability (low, medium, high, or critical)
node inspect-dependencies.js package.json --fail-on=low

# Fail the build if any dependency uses a copyleft license (GPL, AGPL, LGPL)
# (use the included test fixture to try this out)
node inspect-dependencies.js assets/test-license-package.json --fail-licenses="GPL,AGPL,LGPL"

# CI pipeline with strict security policy (fail on medium+)
node inspect-dependencies.js package.json \
  --include-dev --include-peer \
  --fail-on=medium \
  --html=report.html

# Force fresh data, bypassing any cached responses
node inspect-dependencies.js package.json --no-cache

# Share a single cache across multiple projects to avoid redundant API calls
node inspect-dependencies.js package.json --cache-dir=~/.supply-chain-cache

# Inspect only production deps with narrow version history (fastest)
node inspect-dependencies.js package.json --version-history=2 --no-scorecard

Security Signals

The --findings flag expands details for any package that triggers one or more of the following signals:

| Signal | Meaning | |---|---| | vulns | One or more known CVEs or advisories from OSV.dev | | scripts | Package declares lifecycle scripts (preinstall, postinstall, prepare, etc.) | | low_scorecard | OpenSSF Scorecard score below 5 / 10 | | very_recent | Package version was published fewer than 48 hours ago | | no_repo | No source repository URL found in the npm registry entry | | not_found | Package could not be found on the npm registry at all |

Separately from the per-package findings, a KEV alert section is shown at the bottom of the report (above the footer totals in the CLI; above the Findings section in the HTML report) whenever one or more discovered CVEs appear in the CISA Known Exploited Vulnerabilities catalog. Each KEV match shows:

  • Package name and version
  • CVE ID and severity badge
  • Vendor / product as listed by CISA
  • Date the CVE was added to the catalog and the remediation due date
  • Required action text from CISA
  • A ransomware campaign flag when applicable
  • Direct link to the CISA KEV catalog

JSON Output Structure

Each element of the output array represents one inspected package:

{
  "name": "express",
  "versionSpec": "^4.18.2",
  "resolvedVersion": "4.18.3",
  "lockfileVersion": "4.18.3",
  "scope": "dependencies",
  "ecosystem": "npm",
  "sourceRepository": "https://github.com/expressjs/express",
  "notFound": false,
  "collectedAt": "2025-01-15T10:23:00.000Z",

  "registry": {
    "name": "express",
    "publishedHoursAgo": 2160,
    "publisher": "dougwilson",
    "hasInstallScripts": false,
    "repository": "https://github.com/expressjs/express",
    "homepage": "https://expressjs.com",
    "license": "MIT",
    "directDependencies": 30,
    "dependencyCount": 30,
    "devDependencyCount": 14,
    "peerDependencyCount": 0,
    "unpackedSize": 210000,
    "integrity": "sha512-...",
    "tarball": "https://registry.npmjs.org/express/-/express-4.18.3.tgz",
    "maintainers": ["dougwilson", "wesleytodd"]
  },

  "versionHistory": [
    { "version": "4.18.3", "date": "2024-03-01T00:00:00.000Z" },
    { "version": "4.18.2", "date": "2022-10-08T00:00:00.000Z" }
  ],

  "publisherHistory": [
    { "version": "4.18.3", "publisher": "wesleytodd" },
    { "version": "4.18.2", "publisher": "dougwilson" }
  ],

  "vulnerabilities": {
    "summary": {
      "total": 0,
      "critical": 0,
      "high": 0,
      "medium": 0,
      "low": 0,
      "unknown": 0
    },
    "list": [],
    "error": null
  },

  "scorecard": {
    "score": 7.8,
    "repoChecked": "github.com/expressjs/express",
    "checks": [
      { "name": "Code-Review", "score": 10, "reason": "all changesets reviewed" },
      { "name": "Branch-Protection", "score": 8, "reason": "..." }
    ],
    "signals": {
      "maintained": 10,
      "codeReview": 10,
      "vulnerabilities": 10,
      "signedReleases": -1,
      "branchProtection": 8,
      "securityPolicy": 9,
      "dangerousWorkflow": 10,
      "binaryArtifacts": 10,
      "pinned": 2,
      "ciTests": 9
    },
    "error": null
  }
}

Field Reference

| Field | Description | |---|---| | name | Package name as it appears in package.json | | versionSpec | The version range or tag from package.json (e.g. ^4.18.2) | | resolvedVersion | The actual version that was inspected (from lockfile or registry) | | lockfileVersion | The version pinned in package-lock.json, if available | | scope | Which dependency group this came from (dependencies, devDependencies, peerDependencies, optionalDependencies, transitive) | | notFound | true if the package could not be found on the npm registry | | collectedAt | ISO 8601 timestamp of when the data was collected | | registry.hasInstallScripts | true if the package declares any lifecycle scripts | | registry.publishedHoursAgo | How many hours ago the resolved version was published | | versionHistory | Last N versions with publish dates (N set by --version-history) | | publisherHistory | Who published each of the last N versions | | vulnerabilities.summary | Counts by severity from OSV.dev | | vulnerabilities.list | Full advisory details including CVE IDs, aliases, and affected ranges | | scorecard.score | Aggregate OpenSSF Scorecard score out of 10 (null if unavailable) | | scorecard.signals | Individual check scores (−1 = not applicable) |


Data Sources

| Source | URL | Data provided | |---|---|---| | npm Registry | https://registry.npmjs.org | Package metadata, version history, maintainers, install scripts, tarball integrity | | OSV.dev | https://api.osv.dev/v1/query | Known CVEs and security advisories | | OpenSSF Scorecard | https://api.scorecard.dev | Project health (17 automated checks) | | CISA KEV | https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json | Confirmed actively exploited vulnerabilities |

All four sources are public and unauthenticated — no API tokens required.


KEV Alert

After all packages have been scanned, Supply Chain Inspector cross-references every discovered CVE (including OSV aliases such as GHSA-*) against the CISA Known Exploited Vulnerabilities (KEV) catalog. The KEV catalog lists vulnerabilities confirmed by CISA to be actively exploited in the wild, often with a federal remediation due date.

When matches are found:

  • CLI — a bright-red ▲ KNOWN EXPLOITED VULNERABILITIES banner is printed below the Findings section with per-match detail and a direct link to the catalog. The footer chip also shows ▲ N KEV matches.
  • HTML report — a dedicated red alert card section appears above Findings, with a grid of metadata per match (vendor, product, dates, required action, ransomware flag).

A ready-made test fixture is included at assets/test-kev-package.json — it pins known-vulnerable versions of several packages so you can reproduce KEV matches locally:

node inspect-dependencies.js assets/test-kev-package.json

Example CLI output when matches exist:

──────────────────────────────────────────────────────────────────────────────────────────
  ▲ KNOWN EXPLOITED VULNERABILITIES (CISA KEV)  ·  2 matches with actively exploited CVEs
──────────────────────────────────────────────────────────────────────────────────────────

  ● [email protected]  [MEDIUM  ]  GHSA-2m8v-572m-ff2v
    Command Injection Vulnerability
    Vendor / Product:  Npm package — System Information Library for Node.JS
    Added to KEV:      2022-01-18  ·  Due: 2022-02-01
    Required action:   Apply updates per vendor instructions.
    https://www.cisa.gov/known-exploited-vulnerabilities-catalog

  ● [email protected]  [MEDIUM  ]  GHSA-h47j-hc6x-h3qq
    Remote Code Execution Vulnerability in NPM mongo-express
    Vendor / Product:  MongoDB — mongo-express
    Added to KEV:      2021-12-10  ·  Due: 2022-06-10
    Required action:   Apply updates per vendor instructions.
    https://www.cisa.gov/known-exploited-vulnerabilities-catalog

──────────────────────────────────────────────────────────────────────────────────────────

Exit behaviour

KEV matches always cause the script to exit with code 1, independently of --fail-on. This is intentional: a CVE in the KEV catalog has confirmed real-world exploitation right now, making it more urgent than any theoretical severity rating. The two failure paths are complementary and can both fire in the same run:

| Condition | Exit code | |---|---| | KEV match(es) found (and --no-kev not set) | 1 — always | | Vulnerabilities at or above --fail-on threshold | 1 | | No KEV matches and no --fail-on trigger | 0 |

Use --no-kev to opt out of KEV hard-failure (e.g. in offline environments or when triaging KEV matches separately). The KEV catalog is cached for 24 hours alongside other API responses.


pre-commit Integration

Supply Chain Inspector can be used as a pre-commit hook so it runs automatically whenever package.json is staged in any repository.

Setup

Add the following to your repository's .pre-commit-config.yaml:

repos:
  - repo: https://github.com/DenysVuika/supply-chain-inspector
    rev: v1.0.0  # replace with the desired tag or commit SHA
    hooks:
      - id: supply-chain-inspector
        args: [--fail-on=high] # Optional: fail the commit if any high or critical vulnerabilities are found (default: critical)

Then install the hooks (if you haven't already):

pre-commit install

How it works

  • The hook triggers only when package.json is part of the staged files.
  • pre-commit installs the package via npm into an isolated environment — no global install required.
  • The package.json path is passed automatically as an argument.
  • In a monorepo with multiple package.json files, each staged one is scanned independently.

CI Integration

By default, the script exits with code 0 regardless of findings (advisory mode), with two exceptions that always produce exit code 1:

  • KEV matches — any CVE confirmed in the CISA Known Exploited Vulnerabilities catalog causes an immediate hard failure (bypass with --no-kev).
  • --fail-on=<level> — exit code 1 when vulnerabilities at or above the specified severity threshold are found.

Both checks are independent and can both fire in the same run, each printing its own failure box before the process exits.

# GitHub Actions example — fail on high/critical vulns AND any KEV match
- name: Supply chain scan
  run: |
    NO_COLOR=1 node inspect-dependencies.js package.json \
      --findings \
      --fail-on=high \
      --output=supply-chain.json \
      --html=supply-chain.html \
      2>&1 | tee supply-chain-report.txt

# To disable the KEV hard-fail (e.g. triaging KEV matches separately):
#   add --no-kev to the command above

- name: Upload scan results
  uses: actions/upload-artifact@v4
  with:
    name: supply-chain
    path: |
      supply-chain-report.txt
      supply-chain.json
      supply-chain.html

License

See LICENSE.