The spreadsheet that worked fine until it didn’t
I still keep a CVE tracker. It is a spreadsheet on a Synology share, synced with a Git repo I git pull on my laptop, and it lists every advisory that touches anything I run: cPanel and WHM boxes, a handful of Ubuntu VPSes, a couple of OCI instances, the WireGuard endpoint, the Postgres hosts behind a few customer sites. What I stopped doing somewhere in the last two years is letting that spreadsheet decide what gets patched first. It is a fine inventory. It is a bad prioritisation engine.
Here is the failure mode, and it is boring rather than dramatic. The sheet has a column for CVSS base score. For years, that column was the sort order: anything 9.0 and above got a maintenance window that week, 7.0 to 8.9 got the next scheduled reboot, everything below sat in a tab until it aged out. That worked because the window between a vendor advisory and working public exploit code was usually weeks, often months. Somebody with time on their hands had to sit down and write the thing. A CSV sorted by severity gave me enough of a head start.
That assumption is what broke. A high base score tells you the flaw is nasty in the abstract. It says nothing about whether anyone has already written a weaponised exploit, and increasingly the answer is yes within days, sometimes before the vendor’s own advisory page has finished propagating to the mirrors. I have had a Tuesday where three advisories landed with clean remote vectors, all scoring above 9.0, and my sheet ranked them in the wrong order relative to what actually showed up on Shodan against my own IP ranges the following morning.
And the volume went up while my triage hours did not. I have a day job plus customers who file tickets at 11pm. The spreadsheet assumed I could read everything. I cannot.
What follows is the actual stack I use now for vulnerability risk management on my own infrastructure: CVE prioritisation built from an EPSS score and the CISA KEV catalog, a clear-eyed look at where CVSS still earns its column, and how patch management automation fits underneath so that picking the target is the only human step left. The New Stack piece that prompted this is worth reading alongside it, particularly on why the spreadsheet habit is hard to break.
Background: CVSS, EPSS and KEV answer three different questions
The mistake I made for years was treating one number as a verdict. A CVSS base score answers a narrow question: if someone did exploit this flaw, how much damage could they do? It is a measure of potential impact, computed from the attack vector, complexity, privileges required and the effect on confidentiality, integrity and availability. That is useful. It is also completely blind to whether anybody is currently trying.
The vector string makes this obvious once you look at it closely. Something like CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H is a description of the bug itself. Network reachable, low complexity, no privileges, no user interaction, full impact on all three pillars. Nine point eight, straight to the top of the sheet. What that string cannot tell me is whether the maintainer has shipped a patch, whether a proof of concept is circulating, or whether any of my boxes run the affected service with that code path reachable. Historically, a chunk of my 9.8s sat in a category I privately called theoretically bad. Real severe bugs, no known exploitation, no exposure on my kit.
An EPSS score is a probability, expressed between 0 and 1, that a given CVE will be exploited in the wild in the next thirty days. It is generated daily by FIRST from observed exploitation activity, and it moves. A CVE can sit at 0.004 for a month and then jump. That movement is signal, and it is exactly the thing a static CSV cannot hold. Severity and likelihood are separate axes, and conflating them is how a vulnerability risk management process ends up patching the loudest thing rather than the most dangerous thing.
The CISA KEV catalog is the third signal and the most blunt. It lists CVEs with confirmed evidence of exploitation in the wild, and CISA gives federal agencies a binding deadline to remediate each entry. It is far shorter than the full CVE feed. It is also not instant. A flaw can be actively used for a while before it appears there, and some never get added at all, which is why treating KEV as the whole answer leaves gaps.
None of the three knows what is running on your network. That is the fourth input, and it comes from your own asset records: which hosts, which versions, which services actually exposed. A 9.2 with high EPSS on an internal jump box that only your office VLAN can reach is a different afternoon’s work than the same CVE on the box terminating TLS for paying customers.
What’s happening now: AI exploit generation and the questions I keep getting
The change I have actually noticed on my own infrastructure is not the number of CVEs. It is the shrinking gap between a patch landing and someone publishing working exploit code. N-day exploitation used to be a problem you got to on the following maintenance cycle. For anything with a clean remote vector, I now assume a public proof of concept exists within days. The New Stack wrote about this shift recently (AI is speeding up exploits. Vulnerability spreadsheets can’t keep up (opens in new tab)), and the framing matches what I see in my alerts.
A handful of questions keep arriving in my inbox, so here is how I answer them.
Does AI exploit generation actually change anything for a small hosting shop?
It changes the calendar. When exploitation code was expensive to produce, a lot of CVEs stayed theoretical for months. Now the week between disclosure and my weekend maintenance window is the risky stretch, not the month after it. I have moved some patching earlier because of that alone, particularly for anything listening on a public interface.
Should I ignore CVSS and only patch what is in KEV?
KEV is a floor, not a ceiling. Flaws get exploited for a while before they land in the catalog, and some never do, usually the smaller products and self-hosted tools that nobody is reporting on publicly. If the KEV list is my only trigger, I am structurally blind to everything not yet confirmed by someone else.
Is a high EPSS score enough on its own?
No, and this is where the asset record earns its place. High EPSS on a service reachable from the internet is what gets my attention. The same probability on something bound to 127.0.0.1 can sit behind a database migration without me losing sleep. Probability without reachability is an incomplete sentence.
Can patch automation handle the whole decision?
It handles deployment extremely well. Choosing what gets tonight’s window is still a judgment call, and I have not found a tool that makes it for me. A WordPress plugin CVE on a customer’s €9/month shared plan and an OpenSSH flaw on the hypervisor running forty VPS both score the same on a spreadsheet. They are not the same problem, and only I know which one keeps me awake.