Detect vulnerable packages across 12 ecosystems with a flexible, lightweight shell script. Includes built-in GHSA and OSV vulnerability feeds with 200,000+ npm vulnerabilities (plus per-ecosystem feeds for the rest), or use your own custom databases.
package-checker.sh scans your projects for vulnerable dependencies across npm/JavaScript, Python, Go, Rust, Ruby, PHP, Java/JVM (Maven & Gradle), .NET (NuGet), Dart/Flutter, Elixir, Swift, and GitHub Actions workflows. It auto-detects the lockfiles/manifests present and only loads the feeds those ecosystems need.
npm users: nothing changes for you. npm remains the default ecosystem, the npm console output is byte-for-byte identical to previous releases, and the default Docker/Homebrew installs still ship the npm feeds. The other ecosystems are additive.
- 12 Ecosystems: npm, PyPI, Go, Cargo (Rust), RubyGems, Composer (PHP), Maven/Gradle, NuGet, Pub (Dart), Hex (Elixir), Swift, and GitHub Actions — see the ecosystems table
- Built-in Vulnerability Feeds: GHSA and OSV feeds with 200,000+ npm vulnerabilities included, plus per-ecosystem feeds for every other language (auto-updated every 12 hours)
- Detect-then-load: scanning detects the ecosystems in your repo and downloads only the feeds they need — never a single combined all-ecosystems file
- Docker Images Available: Full image (~43MB, npm feeds) or lightweight (~27MB), plus an all-ecosystems variant
- Custom Data Sources: Add your own JSON, CSV, or PURL vulnerability lists
- Scanner Integration: Consume SARIF, SBOM, or Trivy JSON from external tools
- Version Ranges: Define ranges like
>=1.0.0 <2.0.0instead of listing every version - Multiple Package Managers: Full support for npm, Yarn (Classic & Berry/v2+), pnpm, Bun, and Deno — plus one or more lockfiles for each of the other 11 ecosystems
- GitHub Integration: Scan entire organizations or individual repositories directly from GitHub
- Zero Dependencies: Only requires
bash,awk, andcurl - Flexible Configuration: Use CLI arguments or
.package-checker.config.jsonfile
Each ecosystem is discovered by its lockfiles/manifests and scanned against its own GHSA/OSV feed. npm keeps the historical feed filenames (ghsa.purl / osv.purl); every other ecosystem uses ghsa-<eco>.purl / osv-<eco>.purl.
| Ecosystem (purl type) | Lockfiles / manifests scanned | Built-in feed files | --lockfile-types alias(es) |
|---|---|---|---|
npm |
package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml, bun.lock, deno.lock, package.json |
ghsa.purl, osv.purl |
npm, yarn, pnpm, bun, deno |
pypi |
requirements.txt, poetry.lock, uv.lock, pdm.lock, Pipfile.lock |
ghsa-pypi.purl, osv-pypi.purl |
python |
golang |
go.sum, go.mod |
ghsa-golang.purl, osv-golang.purl |
go |
cargo |
Cargo.lock |
ghsa-cargo.purl, osv-cargo.purl |
rust |
gem |
Gemfile.lock |
ghsa-gem.purl, osv-gem.purl |
ruby |
composer |
composer.lock |
ghsa-composer.purl, osv-composer.purl |
php |
maven |
gradle.lockfile, pom.xml |
ghsa-maven.purl, osv-maven.purl |
maven |
nuget |
packages.lock.json |
ghsa-nuget.purl, osv-nuget.purl |
nuget |
pub |
pubspec.lock |
ghsa-pub.purl, osv-pub.purl |
dart |
hex |
mix.lock |
ghsa-hex.purl, osv-hex.purl |
hex |
swift |
Package.resolved |
ghsa-swift.purl, osv-swift.purl |
swift |
githubactions |
.github/workflows/*.yml, *.yaml |
ghsa-githubactions.purl, osv-githubactions.purl |
actions |
When you run a scan, package-checker detects which of these are present and loads only the matching feeds (the separation guarantee: per-ecosystem feed files only, never a single combined file). Override detection with --ecosystems or restrict discovery with --lockfile-types.
- bash — Shell interpreter
- awk (gawk or mawk) — Usually pre-installed
- curl — For remote sources and GitHub API
- Or use Docker images (no installation required)
The whole tool is one self-contained script.sh with zero runtime dependencies on the scan path (only bash, awk, curl — no Node, no Python, no package manager, no install step). jq is only needed to regenerate feeds or open GitHub issues, never to scan.
The important design choice for scale is that vulnerability data is split into one small file per ecosystem — never a single combined bundle. Scanning detects the ecosystems in your repo and loads only their feeds (detect-then-load). A Rust-only project pulls ~0.5 MB; it never touches the 15 MB npm database. This keeps memory bounded and downloads minimal no matter how many ecosystems the tool supports.
| You scan… | Feeds loaded | Size pulled |
|---|---|---|
a Rust repo (Cargo.lock) |
ghsa-cargo + osv-cargo |
~0.6 MB |
a Python repo (requirements.txt) |
ghsa-pypi + osv-pypi |
~5 MB |
a Go repo (go.sum) |
ghsa-golang + osv-golang |
~3 MB |
| an npm repo, GHSA only (default) | ghsa.purl |
~0.9 MB |
| a polyglot repo (npm + Python + Go) | only those 3 ecosystems' feeds | just their sum |
| everything at once | all 24 files | ~35 MB total (npm OSV alone is 15 MB) |
Per-ecosystem feed sizes (GHSA / OSV), so you can see nothing is oversized:
| npm | pypi | golang | maven | composer | cargo | nuget | gem | hex | pub | swift | actions |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0.9M / 15M | 2.1M / 3.1M | 0.9M / 2.1M | 2.1M / 2.1M | 2.1M / 2.1M | 0.3M / 0.3M | 0.7M / 0.9M | 0.2M / 0.4M | 16K / 24K | 4K / 4K | 12K / 8K | 8K / 8K |
The npm OSV feed (mostly malware advisories) is the only large file, and it loads only for npm scans that explicitly opt into OSV.
Feeds are baked at build time via the FEED_ECOSYSTEMS build-arg, so you pick the image size:
| Variant | Image | Baked feeds |
|---|---|---|
…-lite |
ghcr.io/maxgfr/package-checker.sh-lite |
none — bring your own (~27 MB) |
| default | ghcr.io/maxgfr/package-checker.sh |
npm only (~43 MB, unchanged from before) |
…-all |
ghcr.io/maxgfr/package-checker.sh-all |
all 12 ecosystems |
Anything not baked in is fetched on demand at runtime from the per-ecosystem files on GitHub — so even the small default image scans any language.
The easiest way to install and use package-checker:
# Install package-checker
brew install maxgfr/tap/package-checker
# Use it directly (uses default GHSA feed automatically)
package-checker
# Or explicitly specify GHSA feed
package-checker --default-source-ghsa
# Or with both GHSA and OSV feeds
package-checker --default-source-ghsa-osv
# Check specific package version
package-checker --package-name express --package-version 4.17.1
# Scan with custom vulnerability file
package-checker --source custom-vulns.jsonRun directly from the web with your own vulnerability data:
# Run with remote vulnerability source
curl -sS https://raw.githubusercontent.com/maxgfr/package-checker.sh/main/script.sh | bash -s -- --source https://raw.githubusercontent.com/maxgfr/package-checker.sh/refs/heads/main/data/ghsa.purl
# Or with local source file
curl -sS https://raw.githubusercontent.com/maxgfr/package-checker.sh/main/script.sh | bash -s -- --source ./vulns.jsonThe easiest way to get started with built-in vulnerability feeds. Three variants are published (feeds are selected at build time via the FEED_ECOSYSTEMS build-arg):
| Variant | Image | Built-in feeds |
|---|---|---|
| Lite | ghcr.io/maxgfr/package-checker.sh-lite:latest |
none (bring your own) |
| Full (default) | ghcr.io/maxgfr/package-checker.sh:latest |
npm only (ghsa.purl + osv.purl) — identical size/content to before |
| Full — all ecosystems | ghcr.io/maxgfr/package-checker.sh-all:latest |
all 12 ecosystems (ghsa-* / osv-*) |
The default full image bakes in only the npm feeds to stay small; any ecosystem not baked in is auto-fetched at runtime from raw GitHub (detect-then-load). See the Docker documentation for the FEED_ECOSYSTEMS build-arg and offline usage.
# Scan current directory (uses default GHSA feed automatically)
docker run -v $(pwd):/workspace ghcr.io/maxgfr/package-checker.sh:latest
# Or explicitly use GHSA feed
docker run -v $(pwd):/workspace ghcr.io/maxgfr/package-checker.sh:latest --default-source-ghsa
# Or use both GHSA and OSV feeds for comprehensive coverage
docker run -v $(pwd):/workspace ghcr.io/maxgfr/package-checker.sh:latest --default-source-ghsa-osv
# Scan a specific subdirectory
docker run -v $(pwd):/workspace ghcr.io/maxgfr/package-checker.sh:latest /workspace/my-project --default-source-ghsa-osv
# Use with your own data files
docker run -v $(pwd):/workspace ghcr.io/maxgfr/package-checker.sh:latest --source my-vulns.json# Scan current directory (uses default GHSA source automatically)
package-checker
# Scan specific directory (relative or absolute path)
package-checker ./my-project
package-checker /absolute/path/to/project
# Scan a Python project (auto-detects requirements.txt/poetry.lock/… and
# loads the pypi feeds only)
package-checker ./my-python-app --default-source-ghsa-osv
# Scan a polyglot repo (npm + Python + Go in one pass) — each finding is
# labelled with its ecosystem, and JSON/CSV exports carry an `ecosystem` field
package-checker ./polyglot-repo --default-source-ghsa-osv --export-json report.json
# Restrict which ecosystems' feeds are loaded (overrides auto-detection)
package-checker --ecosystems npm,pypi
# Use both GHSA and OSV sources for comprehensive coverage
package-checker --default-source-ghsa-osv
# Use only OSV source instead of default GHSA
package-checker --default-source-osv
# Check specific package version
package-checker --package-name express --package-version 4.17.1
# Check with version ranges
package-checker --package-name lodash --package-version '^4.17.0'
# Scan with custom vulnerability file
package-checker --source custom-vulns.json
# Scan specific folder with custom source
package-checker ./subfolder --source custom-vulns.json
# Multiple sources (built-in + custom)
package-checker --default-source-ghsa-osv --source custom-vulns.csv
# Use configuration file
package-checker --config .package-checker.config.json
# Scan GitHub organization
package-checker --default-source-ghsa-osv --github-org myorg --github-token $GITHUB_TOKENARGUMENTS:
PATH Directory to scan (default: current directory)
Can be relative (./my-project) or absolute (/path/to/project)
OPTIONS:
-h, --help Show help message
--help-ai Show AI help menu
--help-ai prompt Output the AI system prompt (prompt.md)
--help-ai doc Output the full AI guide (docs/ai-guide.md)
-s, --source SOURCE Vulnerability source (repeatable for multiple sources)
--default-source-ghsa Use default GHSA source (default if no source specified)
--default-source-osv Use default OSV source
--default-source-ghsa-osv Use both default GHSA and OSV sources (recommended for comprehensive coverage)
-f, --format FORMAT Data format: json, csv, purl, sarif, sbom-cyclonedx, or trivy-json (auto-detected from extension)
--csv-columns COLS CSV columns: "name,versions" or "1,2"
--package-name NAME Check vulnerability for a specific package name
--package-version VER Check specific version (requires --package-name)
--ecosystem ECO Ecosystem for --package-name (default: npm). One of:
npm, pypi, golang, maven, cargo, gem, composer,
nuget, pub, hex, swift, githubactions
-c, --config FILE Path to configuration file
--no-config Skip loading configuration file
--export-json FILE Export vulnerability results to JSON format (default: vulnerabilities.json)
--export-csv FILE Export vulnerability results to CSV format (default: vulnerabilities.csv)
--github-org ORG GitHub organization to scan
--github-repo owner/repo Single GitHub repository to scan
--github-token TOKEN GitHub token (or use GITHUB_TOKEN env var)
--github-output DIR Output directory for fetched files (default: ./packages)
--github-only Only fetch from GitHub, skip local analysis
--create-multiple-issues Create one GitHub issue per vulnerable package (requires --github-token)
--create-single-issue Create a single consolidated issue with all vulnerabilities (requires --github-token)
--fetch-all DIR Fetch GHSA + OSV feeds for ALL ecosystems to DIR (default: data)
--fetch-osv [ECOS] Fetch OSV feeds; optional comma list of ecosystems (default: all)
--fetch-ghsa [ECOS] Fetch GHSA feeds; optional comma list of ecosystems (default: all)
--only-package-json Scan only package.json files (skip lockfiles)
--only-lockfiles Scan only lockfiles (skip package.json files)
--lockfile-types TYPES Comma-separated lockfile types to scan. npm family:
npm, yarn, pnpm, bun, deno. Other ecosystems: python,
go, rust, ruby, php, maven, nuget, dart, hex, swift,
actions (GitHub Actions workflows)
--ecosystems ECOS Comma-separated ecosystems to load default feeds for,
overriding auto-detection (aliases above or purl types
like npm, pypi, golang, cargo, githubactions)
package-checker.sh supports multiple vulnerability data formats:
Built-in feeds (recommended):
data/ghsa.purl- GitHub Security Advisories, npm (~5,000 vulnerabilities)data/osv.purl- Open Source Vulnerabilities, npm (~207,000 vulnerabilities)data/ghsa-<eco>.purl/data/osv-<eco>.purl- per-ecosystem feeds for every other language (e.g.ghsa-pypi.purl,osv-golang.purl). npm keeps the legacy unsuffixed filenames for backward compatibility.
Custom formats:
- JSON - Simple key-value format with version ranges
- CSV - Tabular format (name, versions)
- PURL - Package URL standard format
- SARIF - Static analysis results (Trivy, Semgrep, CodeQL)
- SBOM CycloneDX - Software Bill of Materials
- Trivy JSON - Native Trivy output format
JSON format:
{
"express": {
"versions": ["4.16.0", "4.16.1"],
"versions_range": [">=4.0.0 <4.17.21"]
}
}CSV format:
name,versions
express,4.16.0
lodash,">=4.17.0 <4.17.21"PURL format:
pkg:npm/lodash@4.17.20
pkg:npm/express@>=4.0.0 <4.17.21
pkg:npm/@babel/traverse@7.23.0
Configuration file (.package-checker.config.json):
{
"sources": [
{
"source": "https://example.com/vulnerabilities.json",
"name": "Company Security Database"
}
],
"options": {
"ignore_paths": ["node_modules", ".yarn", ".git", "dist"]
}
}For complete format specifications, see the Data Formats documentation.
npm lockfiles (exact version matching):
package-lock.json,npm-shrinkwrap.json(npm)yarn.lock(Yarn Classic & Yarn Berry/v2+)pnpm-lock.yaml(pnpm)bun.lock(Bun)deno.lock(Deno)
package.json (dependency checking):
dependencies,devDependencies,optionalDependencies,peerDependencies
Other ecosystems' lockfiles/manifests (see the ecosystems table for the full list):
- Python (
requirements.txt,poetry.lock,uv.lock,pdm.lock,Pipfile.lock), Go (go.sum,go.mod), Rust (Cargo.lock), Ruby (Gemfile.lock), PHP (composer.lock), Maven/Gradle (pom.xml,gradle.lockfile), NuGet (packages.lock.json), Dart (pubspec.lock), Elixir (mix.lock), Swift (Package.resolved), and GitHub Actions workflows (.github/workflows/*.yml)
By default, package-checker scans both lockfiles and package.json files. You can control what gets scanned:
Scan only package.json files:
# Skip all lockfiles, only scan package.json
package-checker --source vulns.json --only-package-jsonScan only lockfiles:
# Skip package.json files, only scan lockfiles
package-checker --source vulns.json --only-lockfilesScan specific lockfile types:
# Only scan yarn.lock files
package-checker --source vulns.json --lockfile-types yarn
# Only scan npm and yarn lockfiles (skip pnpm, bun, deno)
package-checker --source vulns.json --lockfile-types npm,yarn
# Scan only the Python and Go lockfiles in a polyglot repo
package-checker --source vulns.json --lockfile-types python,go
# Combine with --only-lockfiles
package-checker --source vulns.json --only-lockfiles --lockfile-types yarnAvailable lockfile types: npm, yarn, pnpm, bun, deno (npm family) and python, go, rust, ruby, php, maven, nuget, dart, hex, swift, actions (other ecosystems).
You can export scan results to JSON or CSV format for further analysis, reporting, or integration with other tools.
Export to JSON:
# Export with custom filename
package-checker --source vulns.json --export-json results.jsonExport to CSV:
# Export with custom filename
package-checker --source vulns.json --export-csv results.csvExport both formats:
package-checker --source vulns.json --export-json output.json --export-csv output.csvJSON Export Format:
The JSON export includes detailed vulnerability information with metadata:
{
"vulnerabilities": [
{
"package": "express@4.16.0",
"file": "./package-lock.json",
"severity": "medium",
"ghsa": "GHSA-rv95-896h-c2vc",
"cve": "CVE-2022-24999",
"source": "ghsa"
}
],
"summary": {
"total_unique_vulnerabilities": 5,
"total_occurrences": 12
}
}CSV Export Format:
The CSV export includes the same metadata in a tabular format:
package,file,severity,ghsa,cve,source
express@4.16.0,./package-lock.json,medium,GHSA-rv95-896h-c2vc,CVE-2022-24999,ghsa
lodash@4.17.20,./package-lock.json,high,GHSA-p6mc-m468-83gw,CVE-2020-8203,ghsaNotes:
- Exports only include packages where vulnerabilities were found
- Metadata fields (severity, GHSA, CVE, source) are included when available in the vulnerability database
- See the Data Formats documentation for details on adding metadata to your vulnerability sources
Use the reusable GitHub Actions workflow for zero-config vulnerability scanning:
name: Security Check
on:
push:
branches: [ main ]
pull_request:
workflow_dispatch:
schedule:
- cron: '0 0 * * 1' # Weekly on Monday
jobs:
vulnerability-check:
uses: maxgfr/package-checker.sh/.github/workflows/reusable-check.yml@main
with:
use-osv: true # Add OSV in addition to default GHSA
fail-on-vulnerabilities: trueBenefits:
- No installation or configuration required
- Uses built-in GHSA feed by default (auto-updated every 12 hours with 200,000+ vulnerabilities)
- Optionally add OSV feed for even more comprehensive coverage
- Works with npm, Yarn, pnpm, Bun, and Deno projects
- Automatic security reports in PR checks
For more examples and other CI systems (GitLab CI, etc.), see the CI/CD Integration documentation.
Scan an entire organization:
package-checker --github-org myorg --github-token ghp_xxx --source vulns.jsonScan a single repository:
# Public repo (no token needed)
package-checker --github-repo owner/repo --source vulns.json
# Private repo (token required)
package-checker --github-repo owner/private-repo --github-token ghp_xxx --source vulns.jsonFetch only (no analysis):
package-checker --github-org myorg --github-token ghp_xxx --github-only --github-output ./packagesAutomatically create GitHub issues for vulnerabilities:
# Create one issue per vulnerable package
package-checker --github-org myorg --github-token ghp_xxx --source vulns.json --create-multiple-issues
# Create a single consolidated issue with all vulnerabilities
package-checker --github-repo owner/repo --github-token ghp_xxx --source vulns.json --create-single-issueIssue creation modes:
| Flag | Description |
|---|---|
--create-multiple-issues |
Creates one issue per vulnerable package, each with detailed vulnerability info |
--create-single-issue |
Creates one consolidated issue containing all vulnerabilities in a single report |
Both modes include:
- Severity levels with visual indicators (🔴 Critical, 🟠 High, 🟡 Medium, 🟢 Low)
- Links to GHSA advisories and CVE details
- Affected files and versions
- Recommendations for remediation
- Automatic labeling with
security,vulnerabilityanddependenciestags
Note: Both flags require a GitHub token with repo scope to create issues.
You can check if a specific package or version is vulnerable without needing a data source or scanning a project:
# Check if a specific version is vulnerable
package-checker --package-name next --package-version 16.0.3
# Check with version ranges
package-checker --package-name lodash --package-version '^4.17.0'
# List all occurrences of a package in your project
package-checker --package-name expressThis feature creates a virtual PURL internally and scans your project for it.
Use cases:
- Pre-installation checks: "Is this version safe before I
npm install?" - Quick lookups: "Which versions of this package are being used?"
- Security research: "Where is this vulnerable package in my codebase?"
- Version range testing: "Does
^4.17.0cover vulnerable versions?"
Supported version ranges:
- Exact versions:
1.2.3 - Greater/less than:
>=1.0.0 <2.0.0 - Tilde ranges:
~1.2.3(equivalent to>=1.2.3 <1.3.0) - Caret ranges:
^1.2.3(equivalent to>=1.2.3 <2.0.0) - Wildcard:
*(matches any version)
For more detailed information, see the docs/ directory:
- Why package-checker.sh? — Learn why this tool exists and how it complements other vulnerability scanners
- Docker Usage — Complete guide to using Docker images
- Data Formats — Complete specification of JSON, CSV, PURL formats, per-ecosystem PURL shapes, and known limitations
- Vulnerability Feeds — Guide to built-in GHSA/OSV feeds and generating custom feeds
- Vulnerability Scanning Tools — Guide to Trivy, Grype, Syft, OSV-Scanner, and other tools
- Configuration — Detailed configuration reference
- GitHub Integration — Advanced GitHub scanning features
- CI/CD Integration — Examples for GitHub Actions, GitLab CI, and more
- Testing — Testing guide with fixtures and examples
- Contributing — Development workflow, commit conventions, and versioning
- AI Guide — Structured reference for AI assistants to generate custom feeds, commands, and configs
- Security Teams: Maintain internal vulnerability databases
- Compliance: Enforce company-specific security policies
- CI/CD Pipelines: Automated vulnerability checks
- Incident Response: Quick scans during security incidents
- Supply Chain Security: Monitor dependencies across multiple projects
Use an AI assistant (Claude, ChatGPT, Copilot, etc.) to generate custom vulnerability feeds, CLI commands, and configuration files for package-checker.sh.
Built-in help:
# Show AI help menu with all options
package-checker --help-ai
# Output the system prompt — paste into any AI assistant
package-checker --help-ai prompt
# Output the full reference guide — schemas, validation, recipes
package-checker --help-ai doc
# Copy the prompt to clipboard (macOS)
package-checker --help-ai prompt | pbcopyWhat the AI can generate for you:
- Custom vulnerability feeds in JSON, CSV, or PURL format — from a list of CVEs, package names, or security advisories
- CLI commands — the right flags for your specific use case (scanning, exporting, GitHub integration)
- Configuration files —
.package-checker.config.jsontailored to your project - CI/CD pipelines — GitHub Actions, GitLab CI workflows with package-checker
Example prompts you can give to an AI:
"Generate a PURL vulnerability feed for these CVEs: CVE-2020-8203, CVE-2022-24999, CVE-2023-45133"
"Create a .package-checker.config.json that scans only production deps from our internal feed at https://security.company.com/feed.json"
"Write a GitHub Actions workflow that runs package-checker weekly and creates issues for new vulnerabilities"
"Block the package 'malicious-pkg' at all versions in a JSON feed"
Available resources:
prompt.md— System prompt to inject into any AI assistant (paste as context or attach as file)docs/ai-guide.md— Complete reference with schemas, validation rules, and generation recipespackage-checker --help-ai— Condensed guide directly in your terminal
MIT License — see the LICENSE file for details.
Questions or issues? Open an issue on GitHub.