Beta — This project is under active development. APIs, inputs, and output formats may change without notice. Use with caution in production workflows and pin to a specific commit hash.
A GitHub Action that scans Python dependencies for known vulnerabilities and traces each finding back through the dependency chain to the direct dependency that introduced it.
Existing scanners (pip-audit, osv-scanner, grype) tell you what is vulnerable but not why it's in your project. When a transitive dependency has a CVE, you're left guessing which direct dependency pulled it in and whether you can actually fix it.
This action answers: who brought this in, and can I upgrade past it?
Found 3 vulnerabilities in 2 packages
| Package | Version | Vulnerability | Fix | Dependency Chain |
|--------------|---------|----------------|--------|----------------------------------------|
| cryptography | 46.0.3 | CVE-2026-26007 | 46.0.5 | azure-identity > azure-core > cryptography |
| protobuf | 3.20.2 | CVE-2025-4565 | 4.25.8 | **hail** (pinned, blocked) |
| protobuf | 3.20.2 | CVE-2026-0994 | 5.29.6 | **hail** (pinned, blocked) |
### Summary
- 1 fixable via dependency upgrade
- 2 blocked by upstream constraints
Pin to commit hashes, not tags. Tags are mutable — a compromised upstream can repoint a tag to malicious code. Commit SHAs are immutable. Add a
# vXcomment for readability.
- uses: populationgenomics/python-package-scanner@<COMMIT_SHA> # v0- uses: populationgenomics/python-package-scanner@<COMMIT_SHA> # v0
with:
mode: auto # auto | uv | pip
fail-on-vulns: true # exit 1 if vulnerabilities found
comment-on-pr: true # post/update PR comment
ignore-ids: "CVE-2026-0994,GHSA-xxxx"
ignore-packages: "protobuf"- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- run: pip install -r requirements.txt
- uses: populationgenomics/python-package-scanner@<COMMIT_SHA> # v0
with:
mode: pip- uses: populationgenomics/python-package-scanner@<COMMIT_SHA> # v0
with:
path: services/api- uses: populationgenomics/python-package-scanner@<COMMIT_SHA> # v0
id: scan
with:
fail-on-vulns: false
- run: echo "Found ${{ steps.scan.outputs.vuln-count }} vulnerabilities"| Input | Required | Default | Description |
|---|---|---|---|
mode |
no | auto |
Detection mode: auto, uv, or pip |
path |
no | . |
Path to directory containing uv.lock or requirements.txt |
fail-on-vulns |
no | true |
Exit with failure if vulnerabilities found |
comment-on-pr |
no | true |
Post/update PR comment with report |
ignore-ids |
no | "" |
Comma-separated vulnerability IDs to ignore |
ignore-packages |
no | "" |
Comma-separated package names to skip |
| Output | Description |
|---|---|
vuln-count |
Number of vulnerabilities found |
report |
Markdown report content |
- Detects project type —
uv.lockpresent → uv mode, otherwise pip mode - Builds the dependency graph — parses
uv.lock(TOML) or reads installed package metadata viaimportlib.metadata - Queries OSV.dev — checks all packages against the largest open-source vulnerability database (same source as pip-audit and osv-scanner)
- Traces dependency chains — for each finding, walks the graph back to the direct dependency that introduced it
- Classifies findings — fixable (upgrade path exists), blocked (pinned upstream), or ignored
- Reports — markdown table with actionable remediation paths
- stdlib-only — no external Python dependencies; uses
tomllib,importlib.metadata, andurllib.request - Composite action — no Docker, fast startup, works on all runner OSes
- OSV.dev — free, no auth, same DB used by pip-audit and
uv audit - Marker-isolated PR comments — uses an HTML marker to find/update its own comment without clobbering other bots
For PR comments, the workflow needs:
permissions:
pull-requests: writeThe comment-on-pr feature requires the workflow to trigger on pull_request
events. The PR number is read from github.event.pull_request.number, which
is only available on pull_request triggers — not push.
A common pattern for running on both PRs and main:
on:
push:
branches: [main]
pull_request:This avoids double runs — push fires only for main, pull_request fires
for PRs.
python -m scanner.cli --mode uv --path /path/to/project
python -m scanner.cli --mode pip --format json
python -m scanner.cli --ignore-packages protobuf --ignore-ids CVE-2026-0994This is a beta release. Known limitations:
- Duplicate CVE entries may appear when multiple vulnerability databases (GHSA, PYSEC) track the same issue
- pip mode depends on packages being installed in the current environment
- Version comparison uses a simple numeric parser that may not handle all PEP 440 edge cases (epochs, pre-release ordering)
Contributions and bug reports are welcome.
Apache 2.0