Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (supply-chain-inspector) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
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.


Features
- Vulnerability scanning via OSV.dev โ known CVEs and security advisories, severity-ranked (Critical / High / Medium / Low)
- 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.jsonfor 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) 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
npxto run it directly from the registry
Quick Start
# Run directly via npx โ no install needed
npx supply-chain-inspector path/to/package.json
# Or install globally once to get the short "nsci" alias
npm install -g supply-chain-inspector
nsci path/to/package.json
# Or install as a dev dependency and run via npx
npm install --save-dev supply-chain-inspector
npx supply-chain-inspector path/to/package.jsonTypical 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 ยท my-app@1.0.0 ยท 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> [options]
# Via short alias (requires: npm install -g supply-chain-inspector)
nsci <path/to/package.json> [options]
# Or as a local dev dependency
npx supply-chain-inspector <path/to/package.json> [options]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> |
Path to package-lock.json (auto-detected next to package.json if omitted) |
--no-scorecard |
Skip OpenSSF Scorecard lookups (faster, useful offline) |
--no-vulns |
Skip OSV.dev vulnerability lookups |
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 |
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. |
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) |
Exit Code / CI Gate
By default the script exits with 0 regardless of findings. The flags below
turn it into a hard gate that fails with exit code 1 when vulnerabilities at
or above the chosen severity are found โ suitable for CI pipelines, pre-commit
hooks, and lint-staged.
| Flag | Description |
|---|---|
--fail-on=critical |
Exit 1 if any critical CVE is found |
--fail-on=high |
Exit 1 if any critical or high CVE is found |
--fail-on=medium |
Exit 1 if any critical, high, or medium CVE is found |
--fail-on=low / --fail-on=any |
Exit 1 if any vulnerability is found |
--ci |
Shorthand for --fail-on=critical |
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
npx supply-chain-inspector package.json
# Report on stderr + JSON on stdout โ pipe JSON to another tool
npx supply-chain-inspector package.json --json
# Report on stderr + JSON saved to a file โ review both independently
npx supply-chain-inspector package.json --output=results.json
# Write a standalone HTML report โ open report.html in any browser
npx supply-chain-inspector package.json --html=report.html
# HTML report + JSON side by side (useful for both humans and tooling)
npx supply-chain-inspector package.json --html=report.html --output=results.json
# Suppress the report, get only JSON (useful for scripting)
npx supply-chain-inspector package.json --json 2>/dev/null
# Pipe JSON straight into an AI tool
npx supply-chain-inspector package.json --json | llm "analyze these deps"Common Recipes
# Scan all dependency groups, save JSON for later AI analysis
npx supply-chain-inspector package.json \
--include-dev --include-peer \
--output=scan.json
# Generate an HTML report for easy sharing with your team
npx supply-chain-inspector package.json --html=report.html
# Full scan with HTML report, JSON data, and findings detail
npx supply-chain-inspector package.json \
--include-dev --include-peer \
--output=scan.json --html=report.html --findings
# Full deep scan โ all groups, all transitive deps, with findings detail
npx supply-chain-inspector package.json \
--include-dev --include-peer --include-optional --include-transitive \
--findings
# Quick scan โ skip Scorecard (no outbound calls to api.scorecard.dev)
npx supply-chain-inspector package.json --no-scorecard
# High concurrency for large lockfiles (mind API rate limits)
npx supply-chain-inspector package.json --concurrency=10
# CI-friendly: plain text, no color, output to log file
NO_COLOR=1 npx supply-chain-inspector package.json 2>&1 | tee security-report.txt
# Force fresh data, bypassing any cached responses
npx supply-chain-inspector package.json --no-cache
# Share a single cache across multiple projects to avoid redundant API calls
npx supply-chain-inspector package.json --cache-dir=~/.supply-chain-cache
# Inspect only production deps with narrow version history (fastest)
npx supply-chain-inspector package.json --version-history=2 --no-scorecardSecurity 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 |
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) |
All three sources are public and unauthenticated โ no API tokens required.
Pre-commit Hooks / lint-staged
--fail-on / --ci make the script a drop-in lint-staged linter.
lint-staged automatically appends
the staged file path to the command, which aligns perfectly with the script's
positional <path/to/package.json> argument.
Setup
npm install --save-dev husky lint-staged
npx husky init.lintstagedrc.json
{
"package.json": "supply-chain-inspector --ci --include-dev"
}Or inline inside package.json:
{
"lint-staged": {
"package.json": "supply-chain-inspector --ci --include-dev"
}
}.husky/pre-commit
#!/usr/bin/env sh
npx lint-stagedHow it works
- You stage a
package.jsonchange (new dependency, version bump, etc.). - On
git commit, husky runs lint-staged. - lint-staged calls
supply-chain-inspector --ci --include-dev <staged-package.json>. - The script inspects all dependencies, prints the full report to stderr, then checks the vulnerability totals.
- Critical CVEs found โ exits
1โ commit is blocked with a summary line showing the counts (critical:N high:N medium:N low:N). - No issues at the threshold โ exits
0โ commit proceeds normally.
Adjust the threshold to suit your policy:
| Scenario | Flag |
|---|---|
| Block only on confirmed critical CVEs | --ci or --fail-on=critical |
| Block on critical and high | --fail-on=high |
| Block on anything | --fail-on=any |
| Advisory-only (never block) | (omit flag โ default) |
Tip: Pass
--no-cacheif you want lint-staged to always fetch live data rather than serving cached results from a previous run.
CI Integration
Use --fail-on (or --ci) to make the scan a hard gate in your pipeline.
Pipe stderr to your log system and upload the JSON / HTML artifacts for later review.
# GitHub Actions โ fail the build on critical CVEs, upload artefacts
- name: Supply chain scan
run: |
NO_COLOR=1 npx supply-chain-inspector package.json \
--ci \
--include-dev \
--findings \
--output=supply-chain.json \
--html=supply-chain.html \
2>&1 | tee supply-chain-report.txt
- name: Upload scan results
uses: actions/upload-artifact@v4
with:
name: supply-chain
path: |
supply-chain-report.txt
supply-chain.json
supply-chain.htmlFor a non-blocking advisory run (report only, never fails the build), omit
--ci / --fail-on:
- name: Supply chain audit (advisory)
run: |
NO_COLOR=1 npx supply-chain-inspector package.json \
--findings \
--output=supply-chain.json \
2>&1 | tee supply-chain-report.txtLicense
See LICENSE.