Safeguard
Compliance•

CISA BOD 26-04 Explained: Three-Day KEV Deadlines, Forensic Triage, and the Table Behind Them

CISA's BOD 26-04 replaced the familiar 21-day KEV deadline with a 16-row table: 3, 14 or 60 days, plus forensic triage in the worst cases. What it requires, the 7 December 2026 deadline, and a script that looks up the deadline for any CVE.

Safeguard Security Team
Security Research
12 min read

The familiar KEV deadline is gone. For four years, a vulnerability added to CISA's Known Exploited Vulnerabilities catalog usually gave federal agencies 21 days to patch. Since CISA issued Binding Operational Directive 26-04 on 10 June 2026, most new KEV entries carry a three-day deadline, and many come with a second obligation: check whether you've already been compromised.

This post is for security and IT teams at federal agencies, and for the vendors and cloud providers who sell to them. It explains what BOD 26-04 replaced, the 16-row table that now sets deadlines, what "forensic triage" requires, the 7 December 2026 deadline for most of the work, and a script that looks up the deadline for any CVE from CISA's own public data.

The short answer

BOD 26-04 sets federal patch deadlines from four facts: whether the asset is reachable from the internet, whether the CVE is in the KEV catalog, whether an attacker can automate exploitation, and whether exploitation gives partial or total control. The answers produce a deadline of 3 days, 14 days, 60 days, or "fix on system upgrade." When the worst case applies, agencies must also run a forensic triage to look for compromise. The directive revoked BOD 22-01 (the original KEV directive) and BOD 19-02, and with them the federal requirement to prioritize by CVSS score. Agencies have until 7 December 2026, 180 days after issuance, to remediate on the new timelines and tag every externally reachable asset.

What changed in the KEV catalog

You can see the change in the catalog's own JSON feed. This counts the gap between dateAdded and dueDate for entries before and after the directive:

# kev_gaps.py: python3 kev_gaps.py
import json, urllib.request, datetime as dt
from collections import Counter

url = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
kev = json.load(urllib.request.urlopen(url))["vulnerabilities"]
gap = lambda v: (dt.date.fromisoformat(v["dueDate"]) - dt.date.fromisoformat(v["dateAdded"])).days

before = [v for v in kev if v["dateAdded"] < "2026-06-10"]
after = [v for v in kev if v["dateAdded"] >= "2026-06-10"]
print("before 10 June:", len(before), Counter(map(gap, before)).most_common(4))
print("since 10 June: ", len(after), Counter(map(gap, after)).most_common(4))
print("since 10 June, forensicTriage:", Counter((v.get("forensicTriage"), gap(v)) for v in after))

Output against the catalog as published on 13 October 2026:

before 10 June: 1617 [(21, 1025), (14, 254), (181, 238), (3, 31)]
since 10 June:  124 [(3, 101), (14, 23)]
since 10 June, forensicTriage: Counter({('Yes', 3): 81, ('No', 14): 23, ('No', 3): 20})

Before the directive, 21 days was the norm. Since then, 101 of the 124 new entries have a three-day due date, and 81 of those also carry forensicTriage: "Yes", a field that is "No" on every entry added before 10 June. The newest example is CVE-2026-96951, a Windows Shell flaw Microsoft lists as exploited. CISA added it on 13 October with a due date of 16 October and forensic triage required.

One caution about reading the feed. The dueDate is CISA's calculation for the general case, based on whether CISA has evidence the software is typically internet-facing. An agency's actual deadline depends on its own asset, as the table below shows.

The table that sets the deadline

This is Table 1 from the directive's appendix. "Automatable" and "Technical Impact" are CISA's assessments under SSVC (Stakeholder-Specific Vulnerability Categorization), published for every CVE through its Vulnrichment program. "Publicly exposed" is the agency's own call about the specific asset.

#Publicly exposedIn KEVAutomatableTechnical impactDeadline (calendar days)
1YesYesYesTotal3 days + forensic triage
2YesYesYesPartial3 days
3YesYesNoTotal3 days + forensic triage
4YesYesNoPartial14 days
5YesNoYesTotal3 days
6YesNoYesPartial14 days
7YesNoNoTotal14 days
8YesNoNoPartial60 days
9NoYesYesTotal3 days + forensic triage
10NoYesYesPartial14 days
11NoYesNoTotal14 days
12NoYesNoPartial14 days
13NoNoYesTotal60 days
14NoNoYesPartial60 days
15NoNoNoTotalFix on system upgrade
16NoNoNoPartialFix on system upgrade

Three rows deserve attention.

Row 5 is new territory. An internet-facing asset with an automatable, total-control bug gets three days even if it isn't in the KEV. Under the revoked BOD 19-02, the same bug was keyed to its CVSS severity: 15 days if critical, 30 if high.

Row 9 reaches inside the network. An exploited, automatable, total-control bug gets three days plus forensic triage even on an internal asset. Being off the internet buys nothing in the worst case.

Rows 15 and 16 are permission to wait. An internal asset with a non-automatable bug that isn't in the KEV can be fixed at the next scheduled upgrade. CISA says plainly that agencies "do not need to prioritize these vulnerabilities." That is the trade the directive makes: more urgency at the top, explicit room at the bottom.

The clock starts when CISA adds the CVE to the KEV or when the agency first records the vulnerability on an asset in its CDM (Continuous Diagnostics and Mitigation) dashboard, whichever comes first. It also moves with the facts. Pulling a system off the internet changes "publicly exposed" to No and relaxes the deadline. A CVE joining the KEV shortens it.

What "forensic triage" means

"& forensic triage" means remediate within three days and determine whether the asset was already compromised. CISA's implementation guidance sets out six steps with target times measured from the KEV addition:

  1. Scoping (first 2 hours): identify affected systems, activate the triage team, and open an out-of-band communication channel.
  2. Preserve and collect evidence (2 to 24 hours): capture volatile data such as memory first, and keep a collection log.
  3. Patch and stabilize (2 to 24 hours): after evidence is collected, because patching can destroy artifacts.
  4. Contain (6 to 24 hours): without alerting the attacker.
  5. Analyze (24 to 48 hours): unauthorized access, lateral movement, persistence, staging or exfiltration.
  6. Decide on escalation (48 to 72 hours): write a triage report. A confirmed compromise goes to CISA's incident reporting system.

The step timings are recommendations. The triage itself is the requirement. The ordering is the part teams get wrong under pressure: the instinct is to patch first, and the guidance says to collect evidence first where possible.

Look up the deadline for any CVE

Three of the four inputs are public. CISA publishes the KEV feed, and it attaches its SSVC decision points to each CVE record as an "ADP" (authorized data publisher) container named CISA-ADP. This script reads both and prints the deadline for an exposed asset and for an internal one:

#!/usr/bin/env python3
"""Look up the BOD 26-04 remediation timeline for CVE IDs, using CISA's public data.

usage: python3 bod2604.py CVE-ID [CVE-ID ...]
Prints the timeline for an internet-exposed asset and for an internal one.
"""
import json, sys, urllib.request

KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
CVE_API = "https://cveawg.mitre.org/api/cve/"

# BOD 26-04, Appendix A, Table 1: (exposed, in_kev, automatable, total_control) -> timeline
TABLE_1 = {
    (True,  True,  True,  True):  "3 days + forensic triage",
    (True,  True,  True,  False): "3 days",
    (True,  True,  False, True):  "3 days + forensic triage",
    (True,  True,  False, False): "14 days",
    (True,  False, True,  True):  "3 days",
    (True,  False, True,  False): "14 days",
    (True,  False, False, True):  "14 days",
    (True,  False, False, False): "60 days",
    (False, True,  True,  True):  "3 days + forensic triage",
    (False, True,  True,  False): "14 days",
    (False, True,  False, True):  "14 days",
    (False, True,  False, False): "14 days",
    (False, False, True,  True):  "60 days",
    (False, False, True,  False): "60 days",
    (False, False, False, True):  "fix on system upgrade",
    (False, False, False, False): "fix on system upgrade",
}

def fetch(url):
    req = urllib.request.Request(url, headers={"User-Agent": "bod2604-lookup"})
    with urllib.request.urlopen(req, timeout=30) as r:
        return json.load(r)

def ssvc(cve_id):
    """Return (automatable, total_control) from CISA's Vulnrichment ADP entry, or None if absent."""
    record = fetch(CVE_API + cve_id)
    for adp in record.get("containers", {}).get("adp", []):
        if adp.get("providerMetadata", {}).get("shortName") != "CISA-ADP":
            continue
        for metric in adp.get("metrics", []):
            other = metric.get("other", {})
            if other.get("type") == "ssvc":
                opts = {k: v for o in other["content"]["options"] for k, v in o.items()}
                return opts.get("Automatable") == "yes", opts.get("Technical Impact") == "total"
    return None

kev = {v["cveID"]: v for v in fetch(KEV_URL)["vulnerabilities"]}

for cve_id in sys.argv[1:]:
    in_kev = cve_id in kev
    data = ssvc(cve_id)
    if data is None:
        # Implementation guidance: with no Vulnrichment data, CISA assumes "no" and "total".
        automatable, total, note = False, True, " (no Vulnrichment data: CISA default no/total)"
    else:
        automatable, total = data
        note = ""
    print(f"{cve_id}: KEV={'yes' if in_kev else 'no'} automatable={'yes' if automatable else 'no'} "
          f"impact={'total' if total else 'partial'}{note}")
    print(f"  internet-exposed asset: {TABLE_1[(True, in_kev, automatable, total)]}")
    print(f"  internal asset:         {TABLE_1[(False, in_kev, automatable, total)]}")
    if in_kev:
        k = kev[cve_id]
        print(f"  KEV added {k['dateAdded']}, catalog due date {k['dueDate']}, forensicTriage={k.get('forensicTriage')}")

Run against five CVEs on 14 October 2026:

$ python3 bod2604.py CVE-2026-104935 CVE-2026-96951 CVE-2026-70175 CVE-2026-88092 CVE-2021-44228
CVE-2026-104935: KEV=yes automatable=yes impact=total
  internet-exposed asset: 3 days + forensic triage
  internal asset:         3 days + forensic triage
  KEV added 2026-10-13, catalog due date 2026-10-16, forensicTriage=Yes
CVE-2026-96951: KEV=yes automatable=no impact=total
  internet-exposed asset: 3 days + forensic triage
  internal asset:         14 days
  KEV added 2026-10-13, catalog due date 2026-10-16, forensicTriage=Yes
CVE-2026-70175: KEV=no automatable=no impact=total
  internet-exposed asset: 14 days
  internal asset:         fix on system upgrade
CVE-2026-88092: KEV=no automatable=yes impact=total
  internet-exposed asset: 3 days
  internal asset:         60 days
CVE-2021-44228: KEV=yes automatable=yes impact=total
  internet-exposed asset: 3 days + forensic triage
  internal asset:         3 days + forensic triage
  KEV added 2021-12-10, catalog due date 2021-12-24, forensicTriage=No

The fourth line is the clearest illustration of the shift. CVE-2026-88092, a Kestrel request-smuggling bug Microsoft fixed on 13 October, isn't in the KEV and nobody reports exploiting it. On an internet-facing server it still gets three days, because CISA rates it automatable with total impact. The last entry, Log4Shell, shows the catalog's old 14-day due date still recorded on a 2021 entry. Under the new table, the same CVE on any asset would mean three days plus triage.

If a CVE has no Vulnrichment entry yet and isn't in the KEV, the implementation guidance says CISA treats it as not automatable with total impact until data arrives. The script applies the same default.

Dates and duties

WhenWhat agencies must do
10 June 2026 (Phase I)Update vulnerability management policies; report KEV status through the CDM dashboard (or manually, bi-weekly); attest exposed IPs and domains each quarter
9 August 2026 (Phase II, 60 days)Update processes to remediate from the full CVE data and the KEV catalog
7 December 2026 (Phase III, 180 days)Remediate within Table 1 timelines; tag every externally reachable asset by organization, environment, exposure and asset type; report weekly in a machine-readable format if not automated through CDM

The asset tagging is the hard part for most agencies. Table 1 depends on knowing which assets are publicly exposed, and an agency that can't answer that gets CISA's "best effort" fallback. Under that fallback, an asset on a publicly routable IP address, any network device, or software CISA considers generally public-facing is treated as exposed.

If you sell to federal agencies

The directive binds federal civilian agencies, not their suppliers. Contractors are covered only where the contract says so. But agencies are told to review their contracts, and the guidance is explicit about cloud services. FedRAMP-authorized providers coordinate through the FedRAMP program office. Other providers hosting federal assets work directly with the agency. For SaaS, the provider is responsible for application security, and a commercial provider "must report the status of outstanding vulnerabilities" to its agency customer.

In practice, expect federal customers to ask whether you can meet a three-day window on KEV entries in your product, and to write it into contracts. CISA "strongly recommends" exactly that. If your current answer is a 30-day patch SLA keyed to CVSS, it no longer matches how your customer is measured.

The fair criticism

Three days is very short for systems that need change approval, testing and maintenance windows, and the guidance doesn't pretend otherwise: it asks agencies to plan for high-value assets in advance and make "explicit, transparent risk decisions" about availability. The model also leans heavily on two judgments, Automatable and Technical Impact, that CISA makes centrally. An agency that disagrees with a rating still has to meet the deadline it produces.

The alternative was the old model, where a CVSS 9.8 on an isolated lab box demanded the same urgency as one on a VPN concentrator. BOD 26-04 accepts more speed at the top in exchange for real permission to wait at the bottom. For most teams, federal or not, that is a better way to spend limited patching time.

Prioritizing this way works best when exploitation and KEV status sit next to every finding. Safeguard's vulnerability management enriches findings with KEV and EPSS data so teams can sort by real risk rather than CVSS alone. For the scoring background, see our CVSS vs EPSS vs KEV prioritization guide.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.