vuln-prioritizer is a Python CLI for prioritizing known CVEs. It accepts plain CVE lists plus scanner and SBOM exports, enriches them with NVD + EPSS + CISA KEV, and adds optional ATT&CK, asset-context, VEX, waiver, and evidence layers without turning the priority model into a black box.
- Transparent, rule-based prioritization instead of opaque scoring.
- Local-first workflows with saved JSON, HTML reports, snapshots, optional SQLite-backed history views, rollups, and evidence bundles.
- Optional ATT&CK context from local CTID/MITRE data, not heuristic CVE-to-ATT&CK guesses.
- CI-friendly outputs including Markdown summaries, SARIF, GitHub Action support, and policy gates.
- Explicit support for VEX, asset context, waivers, and reproducible review artifacts.
- Waiver lifecycle visibility with active, review-due, and expired states instead of silent long-lived exceptions.
Core commands:
analyze: prioritize findings from CVE lists, scanners, or SBOM exportscompare: show how enriched prioritization differs from CVSS-onlyexplain: explain a single CVE decision in detaildoctor: validate local setup, config, cache, files, and optional live source reachabilitysnapshot create|diff: capture a run and compare before/after statesstate init|import-snapshot|history|waivers|top-services|trends|service-history: persist snapshots in an optional local SQLite store and inspect history, waiver debt, repeated services, or service trendsrollup: aggregate saved analysis or snapshots by asset or serviceinput validate: locally validate CVE lists, scanner/SBOM exports, asset context, and VEX before enrichmentattack validate|coverage|navigator-layer: validate and use local ATT&CK mappingsreport html|evidence-bundle|verify-evidence-bundle: render HTML, build reproducible ZIP evidence packages, or verify bundle integritydata status|update|verify|export-provider-snapshot: inspect cache state, maintain local provider data, and export replayable provider snapshots
Supported inputs:
cve-listgeneric-occurrence-csvtrivy-jsongrype-jsoncyclonedx-jsonspdx-jsondependency-check-jsongithub-alerts-jsonnessus-xmlopenvas-xml
Supported outputs vary by command. The main analyze command supports:
- terminal table
markdownjsonsarif- direct HTML sidecars via
--html-output - Markdown executive summaries via
--summary-output
Other commands expose the formats that fit their contract. For example, report html writes HTML from saved analysis JSON, evidence bundle commands write or verify ZIP bundles, and helper commands such as doctor, snapshot, rollup, state, attack, and data expose command-specific Markdown, JSON, or table output where supported.
This project is:
- a CLI for known CVEs and existing findings
- local-first and reproducibility-oriented
- explicit about data provenance and scoring rules
- designed for vulnerability management, security triage, and evidence generation
This project is not:
- a scanner
- a SIEM
- a ticketing system
- a web application
- a live TAXII harvester
- a heuristic or LLM-based ATT&CK mapper
pipx install git+https://github.com/Noetheon/vuln-prioritizer-cli.git@vX.Y.Z
vuln-prioritizer --helpReplace vX.Y.Z with the GitHub release tag you intend to consume. This README tracks the current main branch, so a tagged public release can legitimately expose a smaller surface than the tip of main. The latest public release is currently v1.1.0.
The repository is PyPI-ready, but the verified public install path is currently the GitHub tag install above. That is a source-at-tag install path, not a GitHub Release asset install path. Public PyPI/TestPyPI publication is wired and documented, but explicitly gated until the repository's trusted-publisher configuration is enabled. When PyPI goes live, the release workflows verify hosted-index installation automatically after publish; until then, the GitHub tag install above remains the supported public path and the release workflow also verifies the same source-at-tag install contract on tag pushes.
- Works after
pipx installalone: commands that use files you create yourself or already have in your own workspace, such ascves.txt,trivy-results.json,analysis.json, andreport.html. - Needs extra local data files: ATT&CK examples require files that you pass via
--attack-mapping-fileand--attack-technique-metadata-file. - Repo checkout only: examples that reference
data/...,docs/..., ormake .... In this repository those paths refer to checked-in fixtures, checked-in docs artifacts, or maintainer targets.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e .[dev]Optional:
cp .env.example .envThen set NVD_API_KEY in .env if you want authenticated NVD access.
printf 'CVE-2021-44228\nCVE-2024-3094\n' > cves.txt
vuln-prioritizer analyze --input cves.txt --format markdown --output report.mdvuln-prioritizer analyze \
--input trivy-results.json \
--input-format trivy-json \
--format json \
--output analysis.json \
--summary-output summary.md \
--html-output report.htmlvuln-prioritizer snapshot create \
--input trivy-results.json \
--input-format trivy-json \
--output after.json
vuln-prioritizer snapshot diff \
--before before.json \
--after after.json \
--format markdown
vuln-prioritizer rollup \
--input after.json \
--by service \
--format markdownvuln-prioritizer report evidence-bundle \
--input analysis.json \
--output evidence.zip
vuln-prioritizer report verify-evidence-bundle \
--input evidence.zip \
--format json \
--output evidence-verification.jsonvuln-prioritizer analyze \
--input cves.txt \
--format markdown \
--output attack-report.md \
--attack-source ctid-json \
--attack-mapping-file ./attack-mapping.json \
--attack-technique-metadata-file ./attack-techniques.jsonThose ATT&CK files are not bundled by a pipx install. If you are working from a repository checkout, the checked-in demo inputs live under data/attack/.
vuln-prioritizer state init --db build/state.db
vuln-prioritizer state import-snapshot \
--db build/state.db \
--input after.json
vuln-prioritizer state top-services \
--db build/state.db \
--days 30 \
--format json \
--output state-top-services.json
vuln-prioritizer state trends --db build/state.db --format json
vuln-prioritizer state service-history --db build/state.db --service paymentsvuln-prioritizer data export-provider-snapshot \
--input cves.txt \
--output provider-snapshot.json
vuln-prioritizer analyze \
--input cves.txt \
--provider-snapshot-file provider-snapshot.json \
--locked-provider-data \
--format json \
--output analysis.jsonUse --cache-only on data export-provider-snapshot when local smoke tests must avoid live provider refreshes.
v1.1.0 adds first-class runtime config via vuln-prioritizer.yml.
The optional SQLite state store is intentionally separate: it is local-only, opt-in, and does not change analyze, report, snapshot, or evidence semantics.
Example:
defaults:
policy_profile: enterprise
# Add ATT&CK defaults only if you keep local mapping files yourself.
# attack_source: ctid-json
# attack_mapping_file: ./attack-mapping.json
# attack_technique_metadata_file: ./attack-techniques.json
commands:
analyze:
format: json
attack:
validate:
attack_mapping_file: ./attack-mapping.json
attack_technique_metadata_file: ./attack-techniques.json
data:
export-provider-snapshot:
cache_only: trueUse it with auto-discovery or explicitly:
vuln-prioritizer analyze --input cves.txt
vuln-prioritizer --config vuln-prioritizer.yml analyze --input trivy-results.json --input-format trivy-json
vuln-prioritizer --no-config analyze --input cves.txtStart here for public CLI usage:
- docs/use_cases.md
- docs/playbooks.md
- docs/support_matrix.md
- docs/benchmarking.md
- docs/contracts.md
- docs/methodology.md
- docs/evidence.md
- docs/integrations/reporting_and_ci.md
- docs/releases/v1.1.0.md
Maintainer / repo-checkout workflows:
- Usage questions and workflow help: GitHub Discussions
- Reproducible bugs and scoped feature requests: GitHub Issues
- Security reports: private vulnerability reporting when enabled, otherwise SECURITY.md
- Contribution rules and local validation: CONTRIBUTING.md
- Support routing: SUPPORT.md
Reference material:
- docs/roadmap.md
- docs/reference_cve_prioritizer_gap_analysis.md
- docs/examples/media/workflow-demo.gif
The repository includes a composite GitHub Action for analyze and report html.
Use it after actions/checkout, because the scanned input files live in the consumer repository, not in the action repository.
In mode: analyze, input and input-format accept newline-delimited values so one action step can merge multiple sources. The action also passes through the CLI's waiver, filter, sort, cache, provider replay, and fail-gate flags for deterministic CI runs.
- uses: actions/checkout@v6
- name: Prioritize vulnerabilities
uses: Noetheon/vuln-prioritizer-cli@vX.Y.Z
with:
mode: analyze
input: |
trivy-results.json
github-alerts-export.json
input-format: |
trivy-json
github-alerts-json
output-format: json
output-path: analysis.json
summary-output-path: summary.md
summary-template: compact
html-output-path: report.html
github-step-summary: "true"
waiver-file: waivers.yml
hide-waived: "true"
fail-on: critical
fail-on-expired-waivers: "true"
sort-by: operational
max-cves: "250"Replace vX.Y.Z with the release tag or commit SHA you want to consume. summary-template is backward-compatible and defaults to detailed. Set it to compact for GitHub step summaries or PR comments, or keep detailed when you want the full executive summary artifact. If a workflow only needs $GITHUB_STEP_SUMMARY, the action can now generate a summary without requiring an explicit summary-output-path.
Common analyze-only Action inputs include waiver-file, hide-waived, fail-on-provider-error, fail-on-expired-waivers, fail-on-review-due-waivers, priority, kev-only, min-cvss, min-epss, sort-by, max-cves, provider-snapshot-file, locked-provider-data, no-cache, cache-dir, cache-ttl-hours, nvd-api-key-env, offline-kev-file, and offline-attack-file.
See docs/integrations/reporting_and_ci.md for the full contract and CI patterns, plus docs/examples/github_action_summary_templates.md for compact vs detailed examples.
Useful local gates:
python3 -m pytest -q
make check
make benchmark-check
make release-check
make demo-sync-check-temp
make package-check-tempIf you change docs, examples, or report artifacts, run make release-check so the committed example outputs stay in sync. Use the *-temp targets when you want the same demo or package validation in a temporary copy without mutating checked-in docs artifacts or dist/.
Current release line:
- stable
v1.1.0 - GitHub tag install path available now
- GitHub Release restored for
v1.1.0 - PyPI and TestPyPI workflows prepared, but live publishing remains explicitly gated until trusted-publisher setup is enabled
