Skip to content

Latest commit

 

History

History
98 lines (70 loc) · 6.32 KB

SPEC.md

File metadata and controls

98 lines (70 loc) · 6.32 KB

PatchRank — Specification

One line

A zero-dependency CLI that ranks each Microsoft Patch Tuesday by evidence of real-world exploitation instead of by vendor severity label.

The problem

Every month Microsoft publishes a security update document. The July 2026 document contained 2,070 CVEs. A sysadmin has to decide, usually within a day, what to deploy first and defend that order to a change board.

The universal shortcut is to sort by Microsoft's severity rating and start with "Critical". That shortcut is wrong, and it is measurably wrong.

Measured on the real 2026-Jul MSRC data (reproducible with patchrank verify 2026-Jul):

  • 91% of "Critical"-rated CVEs (106 of 117) have an EPSS exploit probability below 1%, appear in no CISA exploitation catalogue, and are not flagged as exploited by Microsoft.
  • Exactly two CVEs were confirmed exploited in the wild. Neither was rated Critical. One was rated Moderate with a CVSS of 5.3 (CVE-2026-56164).
  • A "Critical only" filter therefore surfaces 117 mostly-irrelevant items and misses both vulnerabilities attackers were actually using.

Severity measures how bad it would be. It does not measure whether anyone is doing it. Triage needs the second question answered, and the data to answer it is free and public — just scattered across three separate feeds that nobody joins.

Who it is for

Windows sysadmins, IT ops, MSP technicians, and vulnerability-management engineers who run monthly patch cycles. Secondary: security analysts who need a machine-readable monthly risk feed for automation.

What it does

Joins three free, unauthenticated public data sources:

Source Endpoint Contributes
Microsoft MSRC CVRF api.msrc.microsoft.com/cvrf/v3.0/cvrf/{month} CVEs, severity, CVSS, affected products, KB remediations, Microsoft's own exploited / publicly-disclosed flags and Exploitability Index
FIRST.org EPSS epss.empiricalsecurity.com/epss_scores-current.csv.gz Probability the CVE will be exploited in the next 30 days, plus percentile
CISA KEV cisa.gov/.../known_exploited_vulnerabilities.json Confirmed known-exploited catalogue, federal remediation due date, ransomware-campaign association

…then scores every CVE with a transparent, deterministic model that weights evidence of exploitation far above severity, and prints a ranked, filterable, explainable triage list.

User scenarios

  1. Patch Tuesday morning. patchrank triage — see this month's CVEs ranked by real risk, with an ACT NOW band at the top.
  2. Scoped to my estate. patchrank triage -p "Windows Server 2022" -p "Exchange" — only what I actually run.
  3. Justify it to the change board. patchrank triage --top 10 --format markdown — paste straight into the ticket, with the reason each CVE ranked where it did.
  4. Defend a single decision. patchrank explain CVE-2026-56164 — full signal breakdown for one CVE.
  5. Feed a pipeline. patchrank triage --format json --min-score 70 | jq ... — into Slack, Jira, or a dashboard.
  6. Air-gapped workstation. Cache on a connected machine, copy ~/.cache/patchrank, run --offline.
  7. Prove the premise. patchrank verify — recompute the severity-vs-exploitation analysis above on any month, from live data.

The scoring model

Score is 0–100, additive, deterministic, and fully explainable. Every contribution is reported.

Signal Points Rationale
Listed in CISA KEV +40 Confirmed exploited. The strongest signal that exists.
KEV known ransomware use +10 Escalates business impact from theoretical to operational.
Microsoft flags Exploited:Yes +25 Vendor confirms exploitation detected.
EPSS probability +0…30 sqrt(epss) * 30 — square root so that a 4% probability still registers meaningfully instead of rounding to nothing.
Exploitability Index "More Likely" +10 Microsoft's own forward-looking forecast.
Publicly disclosed pre-patch +8 Exploit details already in the open.
CVSS base score +0…12 cvss * 1.2. Deliberately capped low: severity is the least predictive input.
Impact is Remote Code Execution +3 Mild adjustment for attack-chain value.

Capped at 100 and mapped to action bands:

Band Score Meaning
ACT NOW ≥ 70 Exploited or near-certain. Emergency change.
URGENT 50–69 Strong exploitation signal. This cycle, prioritised.
SCHEDULED 25–49 Normal cycle.
ROUTINE < 25 Batch it.

Weights live in one documented table in scoring.py and are covered by tests. No hidden heuristics, no model calls, no network-side logic.

In scope for v1.0

  • triage, explain, verify, products, months, cache commands
  • Filters: product, severity, KEV-only, exploited-only, minimum EPSS, minimum score, top-N
  • Output: coloured terminal table, JSON, CSV, Markdown
  • XDG-aware disk cache with per-source TTL; --refresh and --offline
  • Flexible month parsing (2026-Jul, 2026-07, jul-2026, July 2026, latest)
  • Graceful degradation: if EPSS or KEV is unreachable, still produce MSRC-only output and say so loudly
  • Zero required runtime dependencies

Explicitly NOT in scope for v1.0

  • Deploying patches. This is a decision-support tool. It never touches a machine. That boundary is deliberate: it keeps the tool safe to run anywhere, with no privileges.
  • Non-Microsoft vendors. The MSRC feed is Microsoft-only. Adobe/Oracle/SAP would each need a different parser.
  • A web UI or hosted service. patchapalooza.com already occupies that niche; the gap is automatable CLI output.
  • Inventory awareness. The tool does not know what you run. --product filtering is manual by design; integrating with SCCM/Intune inventory is a roadmap item, not v1.
  • Historical trend analytics. One month at a time.
  • Writing to ticketing systems. Emit Markdown/JSON and let the user pipe it.

Non-functional requirements

  • Python 3.9+, stdlib only, no compiled extensions.
  • Cold run (download + parse 12 MB MSRC + 2.5 MB EPSS + 1.5 MB KEV) completes in reasonable time; warm cached run must feel instant.
  • Never crash on partial or malformed upstream data — degrade and report.
  • Exit codes: 0 success, 1 runtime error, 2 bad usage, 3 no results matched.
  • No telemetry. No network calls beyond the three documented feeds.