Which vulnerable dependencies to fix first, using CISA KEV and EPSS
CVSS tells you how bad a vulnerability could be, not whether anyone is exploiting it. Here is how to add CISA's Known Exploited Vulnerabilities catalog and FIRST's EPSS scores to your triage, with commands you can run today.
Oct 30, 2026 · 3 min read
Run a dependency audit on any project more than a year old and you will get a long list. Sorting it by CVSS severity feels responsible, but it answers the wrong question. CVSS describes how bad a vulnerability could be if exploited. It says nothing about whether anyone is actually exploiting it.
Two free, public data sources close that gap: CISA's Known Exploited Vulnerabilities catalog and FIRST's Exploit Prediction Scoring System.
CISA KEV: evidence of exploitation
The Known Exploited Vulnerabilities catalog is a list of CVEs that the US Cybersecurity and Infrastructure Security Agency has evidence are being exploited in the wild. US federal agencies are required to fix listed vulnerabilities by a deadline. Everyone else can use it as a strong signal: if a CVE is on the list, attackers are using it now.
The catalog is published as JSON:
curl -s https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json \
| jq '.vulnerabilities[] | select(.cveID == "CVE-2021-44228")'
Each entry includes the CVE ID, the date CISA added it (dateAdded), and knownRansomwareCampaignUse, which says whether CISA knows of use in ransomware campaigns.
Two caveats:
- KEV is small on purpose. It holds a few thousand CVEs, a tiny fraction of all published ones, and it is biased towards products governments run. Not being on the list is not evidence of safety.
- It is keyed by CVE. Many package advisories have a CVE alias, but some only have a GHSA or ecosystem-specific ID. Map aliases before you match.
EPSS: a prediction, not evidence
The Exploit Prediction Scoring System, maintained by FIRST, estimates the probability that a CVE will see exploitation activity in the next 30 days. Scores run from 0 to 1, are recalculated daily, and come with a percentile that ranks the CVE against all the others.
Query it for any CVE:
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2021-44228,CVE-2022-24775" \
| jq '.data[] | {cve, epss, percentile}'
EPSS is useful for ordering the long tail. Of two high-severity findings, the one with an EPSS of 0.4 is a far better use of your afternoon than the one at 0.001. But it is a model, not an observation. Treat it as a tiebreaker, never as proof that something is or isn't being exploited.
Putting the signals together
A triage order that holds up in practice:
- Malicious packages. These aren't vulnerabilities but attacks: the package itself is hostile. They usually have no CVE, so neither KEV nor EPSS covers them. Remove them and treat the machines that installed them as compromised. (See our guide to malicious packages.)
- CVEs in KEV. Fix these first, whatever their CVSS score. A medium-severity bug under active exploitation outranks a critical one nobody has a working exploit for.
- Critical and high severity in code that ships. Use your lockfile's dependency scopes: a vulnerability in a test runner or linter matters less than one in your HTTP stack.
- Within each group, sort by EPSS.
- The rest: batch it into routine dependency updates.
Notice what isn't in the list: "is the vulnerable function actually called?" Reachability analysis can answer that for some languages, but it needs your source code. Without it, assume the code path is reachable.
A worked example
Take three findings from a real-looking project:
| Package | Advisory | CVSS | Scope | In KEV | EPSS |
|---|---|---|---|---|---|
| log4j-core 2.14.1 | CVE-2021-44228 | 10.0 | production | yes | very high |
| guzzlehttp/psr7 2.1.0 | CVE-2022-24775 | 7.5 | production | no | low |
| minimist 1.2.5 | CVE-2021-44906 | 9.8 | development only | no | low |
By CVSS alone, minimist (9.8) comes second. With scope and exploitation taken into account, the order is clear: Log4j now, because it is exploited; then guzzlehttp/psr7, because it ships; then minimist in the next maintenance pass, because it never reaches production.
Automating it
You can wire this up yourself: download the KEV feed daily, join it to your audit output on CVE aliases, and add EPSS scores from the API. Lockhound does exactly this for every repository you connect. It refreshes KEV and EPSS daily, ranks findings in this order, shows the source behind each priority, and alerts you when a vulnerability you already have is newly added to KEV.
Read next
- How to find vulnerable packages in composer.lock, and which to fix firstUse composer audit to list known vulnerabilities in a PHP project, read what it tells you, trace transitive packages, and decide what to upgrade first.
- Malicious packages, how they work and how to catch themMalicious packages don't have bugs, they are the attack. How they get into projects, why install scripts matter, how to check your lockfile against known malicious versions, and what to do if you find one.