Skip to main content

Agentic CVE triage CLI: scan a software stack and produce a prioritised PDF risk briefing using NVD, OSV, EPSS, CISA KEV, and Exploit-DB.

Project description

CVE Triage & Risk Briefing Agent

An agentic Python CLI that takes a software stack (stack.json), autonomously enriches each package's known CVEs from public threat-intel sources, scores them by actual exploitability (not just CVSS), and produces a professional PDF risk briefing ready for a CTO/CISO.

The agent uses an OpenAI model (default gpt-4o) as the orchestrator — it decides which tools to call, in what order, and when it has enough data to write the final report. The Python side just runs the tools and feeds results back.

Data sources

  • NIST NVD — authoritative CVE catalogue
  • OSV.dev — best coverage for npm, PyPI, Go, Maven, RubyGems
  • FIRST EPSS — probability of exploitation in the wild (next 30 days)
  • CISA KEV — vulnerabilities confirmed exploited in the wild
  • CIRCL CVE / Exploit-DB — public exploit references

Install

pip install cve-triage-agent

Then create a .env file (or export the variables in your shell):

OPENAI_API_KEY=sk-...
NVD_API_KEY=                # optional — recommended for higher rate limits
OPENAI_MODEL=gpt-4o         # optional — override the default model

Get a free NVD API key at https://nvd.nist.gov/developers/request-an-api-key.

Usage

cve-triage --stack stack.json
# → writes report.pdf
cve-triage --stack stack.json --output briefing.pdf
cve-triage --stack stack.json --format markdown --output briefing.md
cve-triage --stack stack.json --format json --output findings.json
cve-triage --stack stack.json --min-cvss 7.0    # drop low-severity noise

You can also invoke without installing the console script:

python -m cve_triage --stack stack.json

Options

Flag Default Description
--stack required Path to the input stack JSON file
--output report.pdf (or .md / .json to match --format) Output path
--format pdf pdf, markdown, or json
--min-cvss 0.0 Drop findings below this CVSS base score
-v, --verbose off Debug logging in agent_run.log
--version Print version and exit

Input format (stack.json)

[
  { "name": "django",  "version": "4.2.3",   "ecosystem": "PyPI" },
  { "name": "express", "version": "4.18.2",  "ecosystem": "npm"  },
  { "name": "openssl", "version": "3.0.7",   "ecosystem": "other" }
]

Supported ecosystems: PyPI, npm, Maven, Go, RubyGems, NuGet, other. Use other for system packages like nginx or openssl that OSV's ecosystem indices don't cover — NVD will still be queried, plus an ecosystem-agnostic OSV fallback.

A worked example lives at examples/stack.json.

Risk scoring

The composite risk score (0–100) weights:

  • CVSS base severity — 40%
  • EPSS exploitation probability — 35%
  • CISA KEV listing — +20
  • Public exploit available — +10
  • Known ransomware association — +5

Tiers: CRITICAL ≥ 75 · HIGH ≥ 50 · MEDIUM ≥ 25 · LOW < 25.

CVSS floor rules guarantee that a CVE with CVSS ≥ 9.5 is always CRITICAL, ≥ 9.0 is always at least CRITICAL, and ≥ 7.0 is always at least HIGH — exploitability signals can promote a tier but never demote one.

A CVE listed in CISA KEV with CVSS 7.5 will outrank a CVSS 9.8 with EPSS 0.001, which is what you want.

Output

A PDF briefing with:

  • Title block + scan metadata + tier counts
  • Executive summary (150–250 words, plain prose, generated by the LLM after scoring so it can never contradict the tables)
  • Packages-scanned table (every input package, even clean ones)
  • Critical/High findings table (tier-color coded)
  • Per-finding detail blocks with description, why-urgent rationale, remediation, references
  • Medium/Low findings table
  • Methodology + data-source list

Use --format markdown for a plain-text version (handy for diffing) or --format json for downstream tooling.

Architecture

cve-triage-agent/
├── cve_triage/
│   ├── cli.py              CLI entry point (argparse → run_agent)
│   ├── loop.py             Two-pass agent: collect → score → summarise
│   ├── tools.py            NVD / OSV / EPSS / KEV / Exploit-DB integrations
│   ├── scorer.py           Composite risk score + CVSS floor rules
│   ├── reporter.py         Markdown + JSON renderers
│   └── pdf_reporter.py     reportlab Platypus PDF renderer
├── examples/
│   └── stack.json
├── pyproject.toml
└── LICENSE

The agent runs a two-pass loop:

  1. Pass 1 — tool-using loop where the model collects + enriches findings and emits a single findings_json block (no prose, no headers).
  2. The Python side scores every finding and applies CVSS floor rules.
  3. Pass 2 — non-tool call where the model writes the executive summary, anchored to the scored findings (so the prose can never reference tiers that don't exist).

Tool-call traces and HTTP retry warnings land in agent_run.log.

Building and publishing

pip install -e ".[dev]"           # editable install with build/twine
python -m build                    # produces dist/*.whl and dist/*.tar.gz
python -m twine upload dist/*      # publish to PyPI

Update author and URL fields in pyproject.toml before your first publish.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cve_triage_agent-0.1.0.tar.gz (28.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cve_triage_agent-0.1.0-py3-none-any.whl (29.7 kB view details)

Uploaded Python 3

File details

Details for the file cve_triage_agent-0.1.0.tar.gz.

File metadata

  • Download URL: cve_triage_agent-0.1.0.tar.gz
  • Upload date:
  • Size: 28.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.4

File hashes

Hashes for cve_triage_agent-0.1.0.tar.gz
Algorithm Hash digest
SHA256 633acfc7f54ae6084a1fd4551ab9900ab7e747397ed8813325494beb880d1405
MD5 b5f815875cd637de409ede2763fbe05e
BLAKE2b-256 d5def16e1926aba7ff56b6616b0baab853a3e7400bdd365e527cfc40293635f0

See more details on using hashes here.

File details

Details for the file cve_triage_agent-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for cve_triage_agent-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0d6eb04e0e2e80211f29b48af51974eda925196d2b02b6207f8532d978167632
MD5 b8b878a1173a454d95d693a9595285ed
BLAKE2b-256 8dbf8e6b98f64da701823a93b6849c793183136aba554d6de68009d376007ce5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page