Skip to main content

Container CVE Triage: Local Scans, Three Buckets, and Explainable Policies

· 5 min read
MCPBundles

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-slim has 46 unique CVEs and 0 patch-today rows under balanced ( 2 under permissive_patches ); node:20-slim has 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)​

  1. Install MCPBundles Desktop and connect the tunnel.
  2. Bind Container Scan on the Vulnerability Intelligence bundle with Trivy installed locally.
  3. Ask your agent: "Scan node:20-slim with policy_preset balanced."

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​

BucketDefault rule (balanced)
Exploit priorityIn CISA KEV, or EPSS ≥ 50%
Patch todayVendor fix reported and composite tier ≥ HIGH (and not already exploit priority)
DeferEverything 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:

PresetPatch-today barWhen to use
balancedFix exists + tier ≥ HIGHDefault nightly triage
permissive_patchesFix exists + tier ≥ MEDIUMSlim bases with pip/npm fixes
strictFix exists + tier ≥ CRITICALEmergency freeze — libc noise stays defer
on_callLower EPSS exploit thresholdIncident 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):

ImageRoleUnique CVEsExploit priorityPatch today (balanced)Defer
python:3.13-slimAPI backend base4600103 (98% deferrable)
node:20-slimFrontend/widgets base97029136 (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-slim with balanced policy and summarize patch_today."
  • "Scan python:3.13-slim with 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​

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.