The Exploitation Window: Replace Vulnerability SLAs With Maximum Exploitable Time
Rodrigo Garcia
Every vulnerability program eventually hits the same wall. The scanner returns tens of thousands of findings, the policy says fix Criticals in 30 days, and there is no version of the math where the team gets through them. So the program quietly becomes a triage exercise run on gut feel, and the thing that actually gets someone breached turns out to have been sitting in row 4,000 of a spreadsheet, sorted below a hundred theoretical criticals nobody will ever exploit.
The fix is not a better score. It is a better clock. A severity SLA starts counting on the day a scanner reports a finding, which is a date about your tooling rather than about your risk. This framework replaces it with Maximum Exploitable Time, a clock that does not start until a working exploit actually exists and you actually know the finding is there, with a ceiling set by how exposed the asset is.
The Backlog Is Not a Priority List
Start with the shape of the problem, because the shape is what makes the rest obvious. More than 40,000 new CVEs are published in a typical year. Only a fraction of those affect software you actually run. Of the ones you run, only a small minority ever get public exploit code written for them. And of those, only some sit on an asset an attacker can reach from the internet without help.
The collapse from backlog to fix list
24-hour ceiling
Bar widths are illustrative and vary by environment. The point is the order of magnitude: two filters, applied in the right order, turn an unfinishable backlog into a day’s work.
Notice what did the filtering. Not severity. Two questions did all the work: does an exploit exist, and how exposed is the asset. Those same two questions decide whether a clock runs at all and how much time it allows.
CVSS Is Not Enough
CVSS is a severity model. It answers a hypothetical: if this vulnerability were exploited, how bad would the outcome be. That is a genuinely useful thing to know, and it is not the same as knowing what to fix. A base score is calculated once, from the properties of the flaw in isolation, by someone who has never seen your network. It cannot know whether exploit code exists, whether anyone is using it, or whether the affected service is exposed to the internet or sitting on a segmented island.
The practical failure is compression. Roughly half of all published CVEs land in the High or Critical bands. A scoring system where half the population is an emergency has stopped being a prioritization system. When your queue says 8,000 Criticals, the number has no information left in it, and the team starts sorting by whatever else is on the screen.
EPSS Is Not Enough Either
The standard next move is to layer EPSS on top, and it is a real improvement. EPSS estimates the probability that a given CVE will be exploited somewhere in the world in the next 30 days, trained on observed exploitation activity. It correctly demotes the enormous pile of theoretical criticals, and if you have only ever sorted by CVSS, adding EPSS is the single highest-value change you can make.
But EPSS has three limits that matter, and teams that stop here get caught by all three.
The first is that a probability is not proof. EPSS is a forecast about the global population of attackers, not a statement about your organization. A 4 percent score means the CVE probably will not be broadly exploited this month. It does not mean nobody has an exploit for it, and targeted attackers are not a rounding error you get to ignore because the average says so.
The second is that EPSS scores the vulnerability, not the deployment. Every instance of a CVE in your environment carries the identical EPSS score whether it is on your internet-facing firewall or on a laptop in a drawer. The score cannot see your network, which is exactly the information you need to decide what to do first.
The third is timing. EPSS is a leading indicator built on observed activity, which means it rises after exploitation begins to show up in the data. For an internet-facing appliance with a fresh exploit, the gap between public exploit code and mass scanning is frequently measured in days. Waiting for the probability to climb means you are reacting to a signal that only turns on once the campaign is already running.
| Signal | The question it answers | What it cannot see | Role here |
|---|---|---|---|
| CVSS base | How bad is the damage if someone exploits this | Whether an exploit exists, whether anyone is using it, where the asset sits | Tie-breaker only |
| EPSS | How likely is broad exploitation in the next 30 days | Your specific deployment, targeted attackers, the first days after exploit release | Early warning, and a tie-breaker inside a band |
| Exploit maturity | Does working code exist that someone can run today | Whether the attacker can reach your asset | Starts the clock |
| Exposure class | How much work does the attacker have to do to reach this asset | Anything about the vulnerability itself | Sets the ceiling |
| First seen | When did your tooling first observe this finding on this asset | Anything about how long you were exposed before you looked | The other half of the clock start |
Read the last column as the thesis. CVSS and EPSS both describe the vulnerability in the abstract and belong in the model as refinements. The three signals that decide your week are whether working exploit code exists, when you first saw the finding, and how exposed the asset is.
Maximum Exploitable Time
Here is the core move. A severity SLA gives every finding a due date stamped at discovery. That date is wrong in both directions at once: it demands urgency for flaws nobody can exploit, and it fails to react at all on the day one of them becomes weaponized.
Maximum Exploitable Time (MET) replaces it with a clock that only runs when the finding is genuinely dangerous.
Definition
Exploitable time is how long a finding has been both weaponized in the world and known to you. Maximum Exploitable Time is how much of it your policy allows.
first_seen_at, the date your scanners first observed the finding on that asset.remediated_at, or when a credited control breaks the exploit path.exposure_class, then halved or doubled by the modifiers below.unproven, or the asset is isolated. Nothing is counting, because nothing can be done with it.Three consequences fall straight out of that definition, and each one fixes something a severity SLA gets wrong.
A finding with no exploit never starts a clock. It goes to your normal patch cadence and it is not late, because there is nothing to be late for. This is the release valve that makes the rest of the framework affordable. Most of your backlog never starts a clock at all.
The clock can start long after discovery. If a vulnerability sat in your environment for eight months as a theoretical flaw and an exploit drops on Tuesday, its clock starts Tuesday. Not at discovery, and not at CVE publication. Under a severity SLA that finding was either already 240 days overdue, which the team learned to ignore, or comfortably closed as accepted risk. Under MET it becomes live the moment the world changes, with a full and honest ceiling to work inside.
The clock is a measure, not a deadline. A due date is binary and mostly tells you about paperwork. Accumulated exploitable time is a quantity, it aggregates, and it is the closest thing to an honest number for how much genuine risk your organization carried this quarter.
Detection lag is the clock you cannot see
The definition uses whichever of the two dates comes later, and that word is doing real work. It splits your total window of danger into two very different problems, with two very different owners.
Case 1
The exploit lands after you already found the flaw. Most common for CVEs you scan for promptly.
Case 2
The flaw was already weaponized when your scanner finally reached the asset.
Detection lag
Exposed and blind. You cannot remediate what you have not observed, so this is not a remediation failure. It is a discovery and inventory failure, and it is fixed by scanning coverage and cadence, not by the patching team.
Exploitable time
Exposed and informed. This is the window you own and the only one MET caps. Holding the team to a clock that started before they could possibly have known is how SLAs lose credibility.
Separating the two is worth doing even before you change any deadline. A program with a 6-hour median exploitable time and a 45-day median detection lag does not have a patching problem, and no amount of pressure on the remediation team will move the real number. Reporting them together is often the first time an organization sees where its actual exposure comes from.
What Starts the Clock
The clock needs a working exploit, and exploit evidence is not one thing. The CVSS temporal exploit maturity values give you a ladder, and the CISA KEV catalog and its ransomware flag sit above it as confirmation that the theory is now practice.
| Signal | What it means | Where you get it | Clock |
|---|---|---|---|
| kev + ransomware | Named crews are using it in live extortion campaigns | CISA KEV ransomware flag | Runs |
| kev | Confirmed exploited in the wild, not merely demonstrated | CISA KEV catalog, vendor advisories confirming active exploitation | Runs |
| high | Autonomous or widely distributed code. Exploitation needs no skill. | CVSS temporal vector, worm and scanner activity | Runs |
| functional | Reliable code that works in most situations. The practical gate. | Metasploit modules, Nuclei templates, Exploit-DB, public repos | Runs |
| proof_of_concept | Demonstrates the flaw. Needs real work to weaponize. | Researcher write-ups, gists, conference talks | Runs on internet only |
| unproven | Real flaw, nobody has shown how to use it | The CVE record and nothing else | No clock. Patch cadence. |
One nuance worth stating out loud: unproven is a claim about your visibility, not about reality. Exploits exist that nobody has published, and some of what is unproven today will be in KEV next month. That is exactly why maturity has to be re-evaluated continuously rather than stamped once at triage, and why unproven means “normal patch cadence” rather than “ignore forever.” A patch cycle that actually runs is your control for the unknown-unknowns.
What Sets the Ceiling
Every finding that starts a clock gets its ceiling from the asset’s exposure class, because exposure decides how much of the attacker’s work is already finished. There are four, and they are derived from real signals rather than from a spreadsheet column somebody filled in during onboarding: whether the asset is internet-reachable, whether it has listening services, and where it sits in the network tier.
Four exposure classes, four ceilings
Reachable from the public internet. VPN concentrators, firewalls, load balancers, mail gateways, remote access portals, public web apps, file transfer appliances, exposed management interfaces. The attacker needs no prior access, no phishing, and no lateral movement. They connect.
Not internet-facing. This class means broad internal reach: tier 0 and tier 1 infrastructure with listening services that most of the network can talk to. Identity providers, jump hosts, reverse proxies, application servers behind the load balancer, core file and directory services. One hop from a compromised edge device.
The general internal estate: hosts with open ports but no internet route and no broad tier reach. Workstations, departmental application servers, print infrastructure. Reachable only once the attacker is inside and moving laterally.
No listening services, enforced segmentation, air-gapped, or the host has not checked in for months. Tracked and re-evaluated on change, never counted as late.
Crown-jewel assets promote one class. A domain controller or a regulated-data store classified private is treated as public for MET purposes, because the blast radius is disproportionate even though the path is longer.
Read public carefully
It is the most misread label in the set. public does not mean publicly exposed to the internet, which is internet. It means publicly reachable within your network: broadly addressable internal infrastructure. If you adopt this vocabulary, define it in writing on day one, because a team that quietly reads it as internet-facing will invert two of your four ceilings.
The Priority Matrix
Exploit maturity on one axis, exposure class on the other. The cell gives you the priority band, the column gives you the MET ceiling. No debate, no score to argue about, no triage meeting.
exposure →
Two things stand out. The first is how much of the grid is grey and how many cells carry no clock at all: most of your backlog is unproven flaws on internal hosts, and the honest answer for that whole region is that regular patching already handles it. The second is that the top-left corner is small, which is the point. A framework that makes everything urgent has not helped you.
The Two Modifiers
MET starts from exposure, then moves for exactly two reasons. Keeping the list at two is deliberate: every extra modifier is another thing to argue about in a meeting, and the framework’s value is that it ends meetings.
| What the exploit gives the attacker | Why it matters | Effect on MET |
|---|---|---|
| Remote code execution | The whole attack in one step. Nothing else needs to work. | Halved |
| Privilege escalation | Turns a foothold into ownership. The second half of every breach chain. | Halved |
| Authentication bypass | Deletes the control you were relying on to keep them out. | Halved |
| Information disclosure, DoS | Reconnaissance value or an availability problem. Rarely a compromise path on its own. | Unchanged |
| A control that breaks this exploit path | The attacker has real work to do first. Genuine risk reduction, and it should be credited. | Doubled, clock keeps running |
Worked through, this is concrete. A functional RCE on an internet asset has a MET of 12 hours. The same finding behind a WAF rule that blocks the specific exploit gets back to 24. An information disclosure on a private host keeps the flat 30 days. The rule is also what stops the framework being gamed by volume: a public host carrying forty exploitable information-disclosure findings and one functional RCE has exactly one finding on a 3.5-day clock, and the policy says so rather than leaving it to whoever reads the report.
Controls buy time, they do not stop the clock
Doubling MET rather than closing the finding is the important detail. A control is time, not a fix. Two rules keep it from becoming a loophole. It has to break this exploit path, not merely exist somewhere in the environment, because “we have a WAF” is not a mitigation for an exploit that never traverses the WAF. And the finding stays open with its clock running, so when the control is removed, tuned out or bypassed, MET reverts and the finding is immediately visible as over-budget rather than quietly reappearing at zero.
The failure mode to watch for
A control credited once, at triage time, and never re-checked. Six months later the rule has been tuned out of the WAF, the segmentation ACL was relaxed for a migration, and a queue of findings is sitting on doubled ceilings that no longer reflect anything true. Control coverage has to be a live input, not a note in a ticket.
At public, Assume Compromise
internet is where you race the attacker. public is where you accept that you might already have lost that race, and the posture changes accordingly.
The reasoning is straightforward. Internet-facing devices get exploited. It happens to organizations with good programs, because the gap between a vendor advisory on a VPN appliance and mass internet-wide scanning is short enough that even a fast team can miss it, and because those appliances are frequently the hardest things in the estate to patch.
What that means operationally is that public assets do not get the luxury of waiting for a finding to be trending. Every functional-or-better code execution and privilege escalation finding on broad-reach internal infrastructure runs its 3.5-day clock, whether or not it is in KEV, whether or not EPSS thinks it is likely, and whether or not anyone is currently talking about it. You are not predicting which one an attacker will use after they land. You are removing the options.
This is the single instruction that most distinguishes MET from a purely intelligence-driven model. Intelligence tells you where the crowd is going. It does not tell you what the person already inside your network will reach for, and by the time it does, they have used it.
The Whole Framework as a Decision Flow
Everything above collapses into one path that a junior analyst can run without a meeting.
A finding on a known asset
Is exploit maturity functional or better, or is it in KEV?
No → no clock. Normal patch cadence, re-check when intel changes. Stop here.
Yes → continue. Clock starts at the later of exploit availability and first_seen_at.
Read MET off the exposure class
internet 24h · public 7d · private 30d · isolated no clock. Crown jewels promote one class.
Apply the two modifiers
RCE, privilege escalation or auth bypass → halve MET. A control that breaks this exploit path → double it, finding stays open.
A band, a running clock, and a number you can defend
”P0, functional RCE on an internet-facing appliance, MET 12 hours, currently 31 hours exploitable” is an argument nobody has to win twice.
Implementation Kit
The framework is worth nothing if you cannot feed it. Here is what it needs, where to get it free, and how to stand it up in a month.
What you need, and where it comes from
| Input | Free source | Refresh | Hard part |
|---|---|---|---|
| KEV and ransomware flag | CISA KEV catalog (JSON feed) | Daily | None. Start here today. |
| Exploit maturity | CVSS temporal vector where published, plus Exploit-DB, Metasploit and Nuclei indexes | Daily | Temporal vectors are often absent, so you infer maturity from exploit sources. Mapping those back to CVE IDs is messy. |
| Exploit availability date | KEV date added, Exploit-DB publication date, module commit dates | Daily | Easy to overlook and required for the clock. Without a date you have a flag, not a metric. |
| Exploitation probability | FIRST EPSS API | Daily | Nothing technically. Just do not let it become the primary sort. |
| Impact type (RCE, privesc) | CVSS vector fields and CWE on the CVE record | Static | Inconsistent CWE tagging. Vector fields are more reliable. |
| Exposure class | Your own inventory, external attack surface scan, listening-service data, firewall and cloud security group rules | Continuous | Genuinely hard, and the input the whole ceiling rests on |
first_seen_at per finding | Your scanner history, if it is preserved across merges and rescans | Continuous | Many pipelines overwrite it on every scan. If first-seen resets, every clock resets and MET is meaningless. |
| Control coverage | EDR and WAF consoles, segmentation policy, reconciled against the inventory | Continuous | Knowing where the agent is not installed matters more than where it is |
The two rows worth pausing on are the ones nobody plans for. An exploit availability date turns a boolean into a clock, and most teams ingest KEV as a flag and throw the date away. And a stable first_seen_at that survives rescans, deduplication and asset merges is what makes the metric trustworthy: if your pipeline resets first-seen every time a scanner re-reports the same finding, every clock silently restarts and your MET compliance will look perfect while nothing has been fixed.
The MET policy table
This is the part that replaces the “Critical in 30 days” line in your policy document. Adapt the ceilings to what your change process can actually sustain, then hold the line on them.
| Exposure | MET | With RCE / privesc / auth bypass | If you cannot make the ceiling | Escalation |
|---|---|---|---|---|
| internet | 24 hours | 12 hours | Take it off the internet. Isolation stops the clock. Waiting does not. | CISO, immediately |
| public | 7 days | 3.5 days | Documented control that breaks the path, dated, with an owner and a re-check. Doubles MET, does not close it. | Security lead, weekly |
| private | 30 days | 15 days | Standard exception process | Monthly report |
| isolated | No clock | No clock | Confirm the asset still exists. Dead hosts get decommissioned, not tracked forever. | Quarterly review |
any, unproven | No clock | No clock | Nothing special. This is the patch cycle doing its job. | Quarterly coverage metric |
A 30-day rollout
Classify exposure
- List every asset reachable from the public internet. Verify externally, do not trust the CMDB.
- Tag all four exposure classes, and write down what
publicmeans before anyone misreads it. - Tag your crown jewels for promotion.
- Count what you could not classify. That number is a finding.
Build the clock
- Ingest KEV and EPSS daily, keeping the dates, not just the flags.
- Derive exploit maturity from whatever exploit sources you can reach.
- Confirm
first_seen_atsurvives a rescan. Test it before you trust it. - Compute exploitable time and detection lag for every open finding.
Run MET in parallel
- Produce band and MET alongside the existing severity SLA. Do not switch yet.
- Work everything already over MET. It will be a shorter list than you fear.
- Note every disagreement between the two queues.
- The disagreements are your business case.
Make it the policy
- Replace the severity SLA table with the MET table.
- Agree the escalation path for P0 before you need it.
- Report MET compliance and detection lag, not total finding count.
- Set a recurring re-scoring job. Clocks must start and bands must move on their own.
What to tell your auditor
The objection you will hear is that MET does not patch all Criticals in 30 days, and that is true. Answer it in three moves. First, the old policy did not patch all Criticals in 30 days either, it just failed quietly against a number nobody measured. Second, MET is stricter, not looser, on everything that matters: a finding an attacker can actually use on an exposed asset is now due in 12 or 24 hours rather than 30 days. Third, every deferral is explicit, dated, attributed to a named condition, and re-evaluated automatically when that condition changes, which is a stronger control story than a uniform deadline the organization silently misses.
If your regulator mandates fixed timelines, run both. Keep the compliance clock as a backstop and use MET to decide the order of work inside it. They do not conflict: MET tells you what to do on Monday morning, and the compliance clock tells you what has to be closed by quarter end.
Measuring It
Change the metrics with the framework or the old incentives will pull you back. Total open findings is a vanity number that mostly tracks scanner coverage. Replace it with five, all of which fall out of the clock you just built.
MET compliance
Percentage of findings that started a clock and were closed inside their ceiling. This is the headline number and the one that belongs in a board pack. It is honest because the denominator excludes everything that was never exploitable.
Currently over MET
Open findings past their ceiling, broken out by exposure class, with the worst overrun named. On internet this should sit at or near zero most days. If it does not, either your edge is unpatchable or your exposure tagging is too generous.
Median exploitable time
The distribution, not just the breaches. A team at 80 percent compliance with a median well under the ceiling is in a very different position from one that scrapes in at the deadline every time.
Median detection lag
Exploit availability to first_seen_at. Owned by discovery and inventory, not by remediation. If this is large, MET compliance flatters you and the real exposure is upstream.
Clock starts per week
How many findings began a clock without a human touching them, because a CVE entered KEV, an exploit was published, an asset became internet-reachable, or a control came off a host. If this is zero, your inputs are frozen and you have rebuilt a static SLA with extra steps.
One Finding, Two Assets
A short worked example makes the reordering concrete. Take a single CVSS 9.8 remote code execution flaw that appears twice in your environment, with identical base score, identical EPSS and identical exploit maturity.
- Maturity
functional, listed in KEV- Exposure
internet- Impact
- Remote code execution
- Controls
- None on the exploit path
- Clock start
- Exploit predates discovery, so
first_seen_at
P0 · MET 12 hours
- Maturity
functional, same CVE- Exposure
isolated- Impact
- Remote code execution
- Controls
- Endpoint control blocks the technique
- Clock start
- Never starts
P3 · no clock, stays visible
A CVSS-sorted queue puts these two rows next to each other and gives them the same 30-day deadline. MET puts one on a 12-hour clock and never starts one for the other, and it can explain both in a sentence. That sentence is what survives contact with an engineering team that is already busy.
Running It Without Building It
The framework is deliberately implementable anywhere. You can run it on a spreadsheet with the KEV feed, an exposure column and a first-seen date, and doing that this week would be an improvement over what most programs do today. The reason people do not is that the inputs it leans on hardest, accurate exposure classification and a first-seen date that survives every rescan and merge, decay fast and are painful to maintain by hand across a real estate.
That is the substrate Koopic is built to provide, and the vocabulary in this article is its vocabulary. Findings from every scanner are merged onto unified golden-record assets on a CAASM foundation, which is what makes first_seen_at stable: it is a property of the merged finding rather than of whichever tool happened to report it last. Assets carry a derived exposure_class of internet, public, private or isolated, computed from internet-facing flags, listening services and network tier rather than typed in by hand. The CVE catalog is continuously enriched with KEV status and its ransomware flag, EPSS, exploit evidence and CVSS temporal data, so exploit maturity stays current without anyone re-triaging. Compensating controls are tracked per asset, auto-detected or declared, and net out of the score rather than living in a ticket comment. The prioritization engine turns all of it into explainable P0 to P3 bands with a per-factor waterfall, and custom priority rules let you encode the exact matrix above against your own signals.
MET itself is the policy layer you set on top: the ceilings, the modifiers and the escalation path are yours to choose, and the platform’s job is to keep every input under them accurate and current. That matters because the whole metric depends on inputs that move. A clock has to start on its own the day a CVE enters KEV, a ceiling has to tighten on its own when a firewall change turns a private asset into an internet one, and a doubled MET has to snap back on its own when a control comes off a host. Maintaining that by hand is the part nobody sustains.
The fastest way to know whether your queue reorders the way this predicts is to run it against your real environment. See it on your data, connect the tools you already have, and find out how many of your findings are already over a ceiling nobody was measuring.
See it on your data
Work with us as a design partner - we'll show you how risk-based prioritization works on your actual environment.
See it on your data