When a dependency reaches end-of-life, the patches stop but the CVEs keep coming. Reachability and KEV membership decide whether that accumulating backlog is noise or a same-week action.
When a dependency reaches end-of-life, the CVEs do not stop accumulating - the patches do. The last version is a fixed snapshot of vulnerabilities discovered up to that moment, plus every vulnerability discovered afterward that nobody will ever fix. CVSS scores keep arriving. Remediation never does.
Active maintenance means someone receives a CVE report, evaluates it, and ships a patch. EOL means that chain is broken. The code is identical to the last supported release; the attack surface is identical; the only thing that changed is that no one will act on what researchers find next.
The risk compounds in two directions. New CVEs filed against the EOL component accumulate without a patch target - every scanner that reports them is correct, but the remediation path is version replacement, not a point upgrade. Meanwhile, old CVEs that were fixed in the supported branch but never backported remain open permanently. The version pinned in your lockfile is the high-water mark of what was patched before the project closed.
The practical effect is that your SLA clock never stops. A CVE filed eighteen months after EOL still triggers a 7-day critical SLA in most policies. Your team will triage it, confirm no patch exists, and close it as accepted risk - every time, for every new CVE, until the component is replaced. That triage overhead is the hidden cost of deferring the replacement.
Not every EOL component is a high-priority replacement. The deciding question is whether the vulnerable code path is actually reachable from the application's entry points. An EOL library pulled in as a transitive dependency of a build tool that never ships to production is a compliance note. An EOL HTTP client sitting on the request path of your payments API is a 7-day action item.
Call-graph reachability resolves this without guesswork. The SCA engine traces import chains from entry points to the component, then from the component to the functions flagged in the CVE. A CVE that describes a parsing flaw in a function no call path ever reaches is rated differently from one where the sink is reachable from an authenticated endpoint. That distinction collapses the backlog before any human triages it.
// SCA finding for an EOL component with reachability annotation { "component": "com.example:legacy-xml-parser:2.4.1", "eol_date": "2023-06-30", "cves": [ { "id": "CVE-2024-38201", "cvss": 9.1, "epss": 0.72, "kev": true, "reachable": true, "call_path": "PaymentsController.parse -> XmlParser.readExternal" }, { "id": "CVE-2025-11042", "cvss": 7.5, "epss": 0.09, "kev": false, "reachable": false, "call_path": "null (no call path from entry points)" } ] }
The first CVE is on KEV with a reachable call path to the payments controller - it gets a 7-day SLA regardless of EOL status. The second is unreachable; it becomes a tracked backlog item that closes when the component is eventually replaced, not an emergency that pulls the on-call engineer at midnight.
CVE databases track vulnerability identifiers, not maintenance status. A component can be EOL for two years with no new CVEs filed and a vulnerability scanner will report it clean - because it is comparing against an identifier list, not against a support lifecycle database. The two signals are orthogonal and both are necessary.
Lifecycle data comes from sources separate from the NVD feed: endoflife.date publishes structured EOL dates for hundreds of runtimes, frameworks and libraries. Package registries sometimes publish deprecation notices. Some ecosystems have formal long-term-support designations with public end dates. Correlating the installed version against these sources is a distinct check from CVE correlation, and omitting it produces a scanner that sees a clean bill of health on a component with a three-year-old EOL date.
| Signal | Source | What it tells you |
|---|---|---|
| CVE / CVSS | NVD, OSV, vendor advisories | Known vulnerabilities with severity at time of filing |
| EPSS | FIRST EPSS model (daily) | Exploitation probability in the next 30 days |
| KEV | CISA KEV catalog | Certified active exploitation by a threat actor |
| EOL date | endoflife.date, registry metadata | Whether a patch will ever exist for future CVEs |
| Reachability | Call-graph analysis at scan time | Whether the vulnerable code path is reachable in your application |
The posture view merges all five. A component that is reachable, KEV-listed, and EOL is the worst combination: exploitation is confirmed in the wild, a patch does not exist, and the code is on a live call path. That finding sits at the top of the queue regardless of how old the EOL date is.
Most SCA findings close with a version upgrade. EOL findings do not. The remediation path is identifying a maintained alternative, porting the integration, and verifying the replacement under the same scan that flagged the original. Until that work is complete, the finding stays open with a tracked accepted-risk note and a scheduled review date.
Two failure modes to avoid. The first is treating EOL as purely a compliance flag and accepting risk indefinitely without a replacement plan - accepted risk is a state, not a resolution. The second is suppressing the finding entirely because no patch exists, which removes it from the posture view and the SLA clock without actually reducing the exposure. A finding with no patch should be visible and scheduled, not silent.
An EOL component is not a lower-priority finding because the vendor stopped caring. It is a higher-priority one, because the only path to a green posture is a replacement - and the longer that work is deferred, the more CVEs accumulate in a queue that has no merge target.