
Container CVE Triage: Local Scans, Three Buckets, and Explainable Policies
TL;DR
- Vulnerability Intelligence runs Trivy on your Mac via Desktop, enriches with NVD + CISA KEV + EPSS, and buckets every CVE into exploit priority / patch today / defer — each row includes a plain-English reason.
- On our own bases (June 2026 scans):
python:3.13-slimhas 46 unique CVEs and 0 patch-today rows underbalanced( 2 underpermissive_patches);node:20-slimhas 97 unique CVEs and 29 patch-today rows — same scanner, different nightly workload. - Built for security and platform teams who already have Trivy output and need shared rules across client images, not another dashboard that dumps CVSS-sorted noise.
Picture Monday after a base-image rebuild. Trivy finished overnight. The spreadsheet has 103 rows before anyone's had coffee. That's the moment this post is about — not picking Wiz over Snyk, but agreeing what actually patches tonight.
In April we open-sourced an MCP server that combines NIST NVD, CISA KEV, and EPSS into a composite risk score. That solved ranking — why a CVSS 5.0 in active ransomware campaigns should beat a CVSS 9.8 nobody is exploiting.
The next bottleneck is operations: your scanner still dumps hundreds of rows, and every team reinvents spreadsheet triage. Paste-JSON workflows do not scale when you run ten client images a week.
We shipped a hosted path that closes the loop: Desktop runs Trivy on your machine, the cloud enriches findings, and scan_triage buckets every CVE with a bucket_reason you can tune via policy presets.
Try Vulnerability Intelligence on MCPBundles — or keep reading for the bucketing rules and real numbers from our own Dockerfiles.
The workflow (no paste step)
- Install MCPBundles Desktop and connect the tunnel.
- Bind Container Scan on the Vulnerability Intelligence bundle with Trivy installed locally.
- Ask your agent: "Scan
node:20-slimwithpolicy_presetbalanced."
scan_triage shells out to Trivy through the Desktop proxy, then queries NVD + KEV + EPSS in parallel. You still can paste Trivy JSON when Desktop is offline — but the default path is target=, not copy-paste.
Three buckets, same rules every image
| Bucket | Default rule (balanced) |
|---|---|
| Exploit priority | In CISA KEV, or EPSS ≥ 50% |
| Patch today | Vendor fix reported and composite tier ≥ HIGH (and not already exploit priority) |
| Defer | Everything else |
Every row carries bucket_reason — e.g. "defer — EPSS 3.76% below exploit threshold 50%; no vendor fix flagged in scanner output."
High CVSS in defer is intentional. Scanner severity measures impact; EPSS measures likelihood. CVE-2005-2541 shows CRITICAL in Trivy with ~4% EPSS and no fix — paging on CVSS alone would burn your weekend.
Policy presets change the patch queue
Same scan, different policy:
| Preset | Patch-today bar | When to use |
|---|---|---|
balanced | Fix exists + tier ≥ HIGH | Default nightly triage |
permissive_patches | Fix exists + tier ≥ MEDIUM | Slim bases with pip/npm fixes |
strict | Fix exists + tier ≥ CRITICAL | Emergency freeze — libc noise stays defer |
on_call | Lower EPSS exploit threshold | Incident mode — watch more EPSS movement |
Override any preset field: epss_exploit_threshold, patch_today_min_tier, patch_today_requires_fix.
Real numbers from our Dockerfiles
Trivy → NVD + KEV + EPSS → bucket (June 2026, local Desktop scans):
| Image | Role | Unique CVEs | Exploit priority | Patch today (balanced) | Defer |
|---|---|---|---|---|---|
python:3.13-slim | API backend base | 46 | 0 | 0 | 103 (98% deferrable) |
node:20-slim | Frontend/widgets base | 97 | 0 | 29 | 136 (82% deferrable) |
Same toolchain, different ops pressure. The Python base is monitor-and-rebuild-on-cadence. The Node base has libc/dpkg rows worth scheduling this sprint.
Under permissive_patches, python:3.13-slim surfaces 2 patch-today pip CVEs (MEDIUM tier, fixes available) that balanced defers. Policy choice is not cosmetic — it changes what humans review.
What you see in Studio
The scan triage workspace shows policy summary, bucket counts, patch-today rows with reasons, and a CRITICAL in defer — why? section for the top deferred CRITICAL findings. The screenshot above is a real python:3.13-slim run under permissive_patches.
Example agent prompts:
- "Scan
node:20-slimwith balanced policy and summarize patch_today." - "Scan
python:3.13-slimwith permissive_patches — why did CRITICAL CVEs defer?" - "Compare CVSS rank vs composite rank for the latest node:20-slim scan."
Scoring still matters
Bucketing sits on top of the composite score from the April post: CVSS base × EPSS multiplier + KEV bonus + ransomware bonus, clamped 0–10. Buckets answer what to do tonight; composite score answers how scary relative to exploitation reality.
Open source + hosted
- Hosted bundle: mcpbundles.com/bundle/vulnerability-intelligence — Desktop local scan + cloud enrichment + Studio widget.
- Open-source server: github.com/thinkchainai/vulnerability-intelligence-mcp — same scoring math, pip install, paste-JSON triage when you self-host.
Not a Wiz/Snyk replacement for coverage. The win is consistent prioritisation rules across environments when you already have scanner output and need humans to agree on what patches tonight.