Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Understanding CVE, CVSS and EPSS to prioritise

By updated

Improve this page

A scanner reports a list of CVEs with scores such as 9.8 Critical or 5.5 Medium, and the question comes straight away: where do you start? This lesson gives the three signals that let you triage: the CVE, the public identifier of a flaw, the CVSS, which estimates its severity, and the EPSS, which estimates the probability that it will be exploited, complemented by the KEV catalogue of flaws that are actually exploited. It is for a DevOps engineer or a developer who reads scan reports. The values quoted were collected on 1 October 2026 from FIRST, the NVD and CISA.

What you will learn

  • Decode a CVE identifier and know what it contains, and what it does not
  • Interpret a CVSS score and recognise its limits
  • Query the EPSS and the KEV catalogue for a vulnerability
  • Prioritise a list of CVEs by combining severity, exploitation and exposure
  • Explain why "0 CVEs" does not mean "0 risk"
  • Link this triage to requirements SOCLE-VLN-INV-2 (in French) and SOCLE-VLN-VEX-2 (in French) of the SOCLE framework

What is a CVE?

A CVE (Common Vulnerabilities and Exposures) is the public identifier of a known vulnerability, assigned by the CVE programme. Before this catalogue, each vendor named the same flaw in its own way, and two alerts could describe the same problem without anyone knowing. With the CVE, a scanner, a vendor advisory and a ticket designate the same flaw with the same identifier, which lets you look for the fix and compare tools.

How do you read an identifier?

An identifier takes the form CVE-YEAR-NUMBER, for example CVE-2024-3094, the backdoor discovered in the xz compression library. Contrary to a common belief, the year is the one in which the identifier was assigned, not necessarily the year of discovery or publication, and the number is a simple sequence, with no meaning for severity nor precise chronological order. CVE-2024-3094 was published in the NVD on 29 March 2024.

What a CVE contains, and what it does not

A CVE record carries an identifier, a short description of the problem and references (vendor advisories, fixes). It does not necessarily carry a score: that is added afterwards, by the NVD or by the vendor. Nor does it say whether the flaw is exploited in the wild, or whether a fix exists for your version. These three pieces of information come from other sources, described below.

CVSS: the severity score, from 0 to 10

The CVSS (Common Vulnerability Scoring System), maintained by FIRST, rates the theoretical severity of a flaw from 0 to 10. The score is computed from a vector that answers a few questions: through which access is the attack made (network, local, physical), is the attack complex, does it require prior privileges or a user action, and what is the impact on confidentiality, integrity and availability.

ScoreLevel
0None
0.1 to 3.9Low
4.0 to 6.9Medium
7.0 to 8.9High
9.0 to 10Critical

The vector can be read and explains the score. Measured in the NVD: CVE-2024-3094 (xz) gets 10.0 with the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H: network attack, low complexity, no privilege or user action, maximum impact. CVE-2021-23337, the lodash flaw met in the SCA lesson, gets 7.2: its vector carries PR:H, the attacker must already hold high privileges, which lowers the rating. Version 4.0 of CVSS has existed since late 2023, but these two records only carry a version 3.1 score: always check the version of the score you are comparing.

EPSS: will the flaw be exploited?

The EPSS (Exploit Prediction Scoring System), also published by FIRST, answers another question: what is the probability that a flaw will be exploited in the next 30 days? It is recomputed every day from real observations of malicious activity and the characteristics of the flaw. It complements CVSS instead of replacing it: a serious flaw that is rarely attacked and a medium flaw that is heavily attacked are not handled in the same order.

Querying the FIRST API

The public FIRST API answers without an account, in JSON. Here is the response collected for CVE-2024-3094:

Terminal window
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3094"
{
"status": "OK",
"status-code": 200,
"version": "1.0",
"access": "public",
"total": 1,
"offset": 0,
"limit": 100,
"data": [
{
"cve": "CVE-2024-3094",
"epss": "0.859740000",
"percentile": "0.997240000",
"date": "2026-09-29"
}
]
}

Two fields are read together. epss is a probability between 0 and 1: 0.859740000 reads as about 86%, not 0.86%. percentile places the flaw relative to all the others: 0.997240000 means it is more likely to be exploited than 99.7% of scored CVEs. The date field is a reminder that the score changes every day: a score collected six months ago no longer describes the situation.

The KEV catalogue: confirmed exploitation

The KEV (Known Exploited Vulnerabilities) catalogue from CISA, the US cybersecurity agency, lists the flaws whose exploitation is confirmed, no longer merely probable. Measured on 1 October 2026: it holds 1,730 entries. It contains CVE-2021-44228 (Log4Shell, added on 10 December 2021) and CVE-2023-44487 (HTTP/2 Rapid Reset), but not CVE-2024-3094: despite its CVSS of 10.0 and its EPSS of 0.86, the xz backdoor was spotted before being exploited at scale. KEV and EPSS therefore do not say the same thing, which is why you check both.

Scanners that display the EPSS

Not all scanners report this information. Measured on the node:14 image, an old Node.js image that piles up vulnerabilities: Grype 0.119.0 adds an epss field and a knownExploited marker taken from the KEV to each match, and can sort by exploitation probability. Trivy 0.74.0 carries no EPSS field in its JSON report. Here is an extract of Grype's output, sorted by EPSS:

Terminal window
grype node:14@sha256:2cafa3fbb0b6529ee4726b4f599ec27ee557ea3dea7019182323b3779959927f --sort-by epss
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
libnghttp2-14 1.36.0-2+deb10u1 1.36.0-2+deb10u2 deb CVE-2023-44487 High 100.0% (99th) 78.8 (kev)
node 14.21.3 *18.18.2, 20.8.1 binary CVE-2023-44487 High 100.0% (99th) 78.8 (kev)
libsystemd0 241-7~deb10u9 (won't fix) deb CVE-2023-50387 High 100.0% (99th) 75.0
libwebp6 0.6.1-2+deb10u1 0.6.1-2+deb10u3 deb CVE-2023-4863 High 100.0% (99th) 85.6 (kev)

The EPSS column gives the probability and the percentile, (kev) flags a confirmed exploitation, and RISK is a score specific to Grype, whose formula belongs to it: use it to sort, not as an absolute measure. Note the (won't fix) line: the distribution vendor will not fix this package, and the only way out is to change the base image.

Combining the signals to decide

None of the three signals is enough on its own. The CVSS gives the severity if the attack succeeds, the EPSS gives the probability that it will be attempted, the KEV says that it already has been. A fourth signal is missing, one that only you know: the exposure of the component. The following table gives a starting policy, to adjust to your context.

SituationSignalsAction
Confirmed exploitationpresent in the KEVFix immediately
Serious and probably exploitedCVSS ≥ 9 and high EPSSFix immediately
Serious, rarely exploitedCVSS ≥ 9, low EPSSFix this week
Medium but heavily exploitedCVSS 4 to 6, high EPSSFix this week
Low and rarely exploitedCVSS < 4, low EPSSSchedule or accept

Exposure adjusts each row: the same flaw moves ahead of the others on a public API and behind them on an isolated test environment. The SOCLE framework makes it a requirement: SOCLE-VLN-VEX-2 asks for a contextual prioritisation, rather than one based on CVSS alone.

Why "0 CVEs" does not mean "0 risk"

A "0 CVEs" report only means: among the known and catalogued flaws in the scanner's database, none matches the components it managed to detect. It covers neither flaws that are still unknown (0-days), nor components the scanner did not see, such as a binary copied by hand into the image, nor flaws that are published but not yet analysed by the database it queries.

The two scanners measured on node:14 illustrate this: Grype finds 2,032 matches there, and Trivy reports 1,455. They read neither the same databases, nor the components in the same way. Combining two tools reduces the blind spots, without removing them.

Above all, a large part of the risk has no CVE at all. A database reachable without a password, an API key published by mistake or the absence of backups are not software vulnerabilities, and no CVE scanner finds them. They fall under other controls: configuration audit with Lynis (in French), secret detection with Gitleaks, architecture review.

RiskExampleCVE?
MisconfigurationDatabase open without a passwordNo
Human errorAPI key published on GitHubNo
Weak architectureNo backup, no monitoringNo
Unknown flaw0-day discovered tomorrowNot yet

What should you do with a list of CVEs?

A list of fifty CVEs does not call for fifty immediate actions. The triage is done with three questions, in this order, and each one shrinks the list before the next.

  1. Where is the component? Exposed on the internet, reachable by partners, internal, or confined to a test environment.
  2. What do the signals say? Presence in the KEV, EPSS, CVSS, in that order of weight.
  3. Which action? Fix, mitigate or accept.

The three actions are not equivalent. Fixing means updating the component, the only way out that removes the risk. Mitigating means reducing the exposure while waiting for the fix, through network filtering or an access restriction. Accepting means documenting why you are not fixing, for a limited period. The diagram below sums up this triage, from the raw list to one of the three actions.

Triage of a list of CVEs: you start from the list reported by the scanner, look first at the exposure of the component (internet, internal, test), then at the KEV, EPSS and CVSS signals in that order, to reach one of the three actions: fix with an update, mitigate while waiting for the fix, or accept in a documented way and with an expiry.List of CVEsreported by the scannerExposure:internet, internal, testSignals:KEV, then EPSS, then CVSSFix:updateMitigate while waitingfor the fixAccept: documented,with an expiry
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

On a fleet of servers, the same triage applies at scale: the Rudder CVE plugin (in French) detects vulnerabilities on each node and drives the update campaigns.

Key points

  1. A CVE is a public identifier; its year is the year of assignment, not necessarily of discovery.
  2. CVSS measures the severity if the attack succeeds; its vector explains the rating.
  3. EPSS estimates the probability of exploitation within 30 days; 0.86 reads as 86%, and it changes every day.
  4. The KEV lists confirmed exploitations: CVE-2024-3094, CVSS 10.0, is not in it.
  5. Grype displays the EPSS and the KEV; Trivy 0.74.0 does not carry the EPSS.
  6. "0 CVEs" covers neither 0-days, nor unseen components, nor risks without a CVE.
  7. You triage by exposure, then KEV, EPSS and CVSS; an acceptance is documented and expires.
  8. Evidence expected by SOCLE-VLN-INV-2 and VEX-2: an inventory enriched with KEV and EPSS, and a contextual prioritisation.

Knowledge check

Check that you have the essentials of this lesson. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Official resources

The four sources of this lesson are public and can be consulted without an account.

ResourceWhat it isLink
CVE ProgramThe official catalogue of identifierscve.org
NVDCVEs enriched with their CVSS scoresnvd.nist.gov
EPSSFIRST's exploitation probabilitiesfirst.org/epss
KEVConfirmed exploitations, by CISAcisa.gov/known-exploited-vulnerabilities-catalog

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn