CISO Guides 18 min read

The Exploitation Window: Replace Vulnerability SLAs With Maximum Exploitable Time

RG

Rodrigo Garcia

· Updated July 21, 2026

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

All CVEs published this year40,000+
the universe
Present somewhere in your environmentthousands
your backlog
Has working public exploit codelow single-digit %
the clock starts here
Exploitable and internet-exposeda list you can finish

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.

SignalThe question it answersWhat it cannot seeRole here
CVSS baseHow bad is the damage if someone exploits thisWhether an exploit exists, whether anyone is using it, where the asset sitsTie-breaker only
EPSSHow likely is broad exploitation in the next 30 daysYour specific deployment, targeted attackers, the first days after exploit releaseEarly warning, and a tie-breaker inside a band
Exploit maturityDoes working code exist that someone can run todayWhether the attacker can reach your assetStarts the clock
Exposure classHow much work does the attacker have to do to reach this assetAnything about the vulnerability itselfSets the ceiling
First seenWhen did your tooling first observe this finding on this assetAnything about how long you were exposed before you lookedThe 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.

CLOCK STARTSat whichever comes later: the date a working exploit became available, or first_seen_at, the date your scanners first observed the finding on that asset.
CLOCK STOPSat remediated_at, or when a credited control breaks the exploit path.
CEILINGset by the asset’s exposure_class, then halved or doubled by the modifiers below.
NO CLOCKif exploit maturity is 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.

known, not exploitable
EXPLOITABLE TIME
remediated
↑ first_seen_at
↑ exploit published (clock starts)
↑ remediated_at

Case 2

The flaw was already weaponized when your scanner finally reached the asset.

DETECTION LAG
EXPLOITABLE TIME
remediated
↑ exploit published
↑ first_seen_at (clock starts)
↑ remediated_at

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.

SignalWhat it meansWhere you get itClock
kev + ransomwareNamed crews are using it in live extortion campaignsCISA KEV ransomware flagRuns
kevConfirmed exploited in the wild, not merely demonstratedCISA KEV catalog, vendor advisories confirming active exploitationRuns
highAutonomous or widely distributed code. Exploitation needs no skill.CVSS temporal vector, worm and scanner activityRuns
functionalReliable code that works in most situations. The practical gate.Metasploit modules, Nuclei templates, Exploit-DB, public reposRuns
proof_of_conceptDemonstrates the flaw. Needs real work to weaponize.Researcher write-ups, gists, conference talksRuns on internet only
unprovenReal flaw, nobody has shown how to use itThe CVE record and nothing elseNo 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

internetMET 24 hours

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.

publicMET 7 days

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.

privateMET 30 days

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.

isolatedno clock

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.

maturity ↓
exposure →
internet
MET 24h
public
MET 7d
private
MET 30d
isolated
no clock
kev + ransomware
P0
P0
P1
P3
kev
P0
P1
P1
P3
high / functional
P0
P1
P2
P3
proof_of_concept
P1
P2
no clock
P3
no clock
P3
unproven
P2
no clock
P3
no clock
P3
no clock
P3
P0 drop everything: patch or take it offlineP1 jumps the queueP2 next scheduled windowP3 patch cadence or trackno clock band assigned for ordering, MET not running

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 attackerWhy it mattersEffect on MET
Remote code executionThe whole attack in one step. Nothing else needs to work.Halved
Privilege escalationTurns a foothold into ownership. The second half of every breach chain.Halved
Authentication bypassDeletes the control you were relying on to keep them out.Halved
Information disclosure, DoSReconnaissance value or an availability problem. Rarely a compromise path on its own.Unchanged
A control that breaks this exploit pathThe 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.

Start

A finding on a known asset

Gate

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.

Ceiling

Read MET off the exposure class

internet 24h · public 7d · private 30d · isolated no clock. Crown jewels promote one class.

Adjust

Apply the two modifiers

RCE, privilege escalation or auth bypass → halve MET. A control that breaks this exploit path → double it, finding stays open.

Result

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

InputFree sourceRefreshHard part
KEV and ransomware flagCISA KEV catalog (JSON feed)DailyNone. Start here today.
Exploit maturityCVSS temporal vector where published, plus Exploit-DB, Metasploit and Nuclei indexesDailyTemporal vectors are often absent, so you infer maturity from exploit sources. Mapping those back to CVE IDs is messy.
Exploit availability dateKEV date added, Exploit-DB publication date, module commit datesDailyEasy to overlook and required for the clock. Without a date you have a flag, not a metric.
Exploitation probabilityFIRST EPSS APIDailyNothing technically. Just do not let it become the primary sort.
Impact type (RCE, privesc)CVSS vector fields and CWE on the CVE recordStaticInconsistent CWE tagging. Vector fields are more reliable.
Exposure classYour own inventory, external attack surface scan, listening-service data, firewall and cloud security group rulesContinuousGenuinely hard, and the input the whole ceiling rests on
first_seen_at per findingYour scanner history, if it is preserved across merges and rescansContinuousMany pipelines overwrite it on every scan. If first-seen resets, every clock resets and MET is meaningless.
Control coverageEDR and WAF consoles, segmentation policy, reconciled against the inventoryContinuousKnowing 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.

ExposureMETWith RCE / privesc / auth bypassIf you cannot make the ceilingEscalation
internet24 hours12 hoursTake it off the internet. Isolation stops the clock. Waiting does not.CISO, immediately
public7 days3.5 daysDocumented control that breaks the path, dated, with an owner and a re-check. Doubles MET, does not close it.Security lead, weekly
private30 days15 daysStandard exception processMonthly report
isolatedNo clockNo clockConfirm the asset still exists. Dead hosts get decommissioned, not tracked forever.Quarterly review
any, unprovenNo clockNo clockNothing special. This is the patch cycle doing its job.Quarterly coverage metric

A 30-day rollout

Week 1

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 public means before anyone misreads it.
  • Tag your crown jewels for promotion.
  • Count what you could not classify. That number is a finding.
Week 2

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_at survives a rescan. Test it before you trust it.
  • Compute exploitable time and detection lag for every open finding.
Week 3

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.
Week 4

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.

Asset AVPN appliance
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

Asset Bsegmented lab host
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