Call the FIRST API epss method with one or more CVE IDs separated by commas. Each result returns the cve, an epss probability, a percentile and a date, all as strings. Add the time series scope for history. Public calls are limited to 1,000 requests per minute, so batch IDs and cache.
What EPSS is
EPSS, the Exploit Prediction Scoring System, is published by FIRST and expresses the likelihood that a CVE will be exploited. It is a probability for a CVE, updated by date, not a severity rating. A high EPSS and a high CVSS are different statements. The first says exploitation is likely. The second says the impact would be bad.
A basic query
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2021-44228"
I ran this against the public API. The response held a status of OK, status code 200, version 1.0, access public, total, offset, limit and a data array. Each data entry had four fields: cve, epss, percentile and date. For the sample CVE, the date was the day before my request, which tells you the data refreshes daily.
Field meanings
| Field | Meaning | Type in the response |
|---|---|---|
| cve | The identifier | String |
| epss | Estimated probability of exploitation | String such as 0.99999 |
| percentile | Relative rank of this score among other CVEs | String |
| date | The day the score applies to | String |
Both numbers arrive as quoted text, so convert them to a numeric type before comparing. Percentile is the better field for ranking, since raw probabilities cluster near zero for most CVEs.
Several CVEs and history
Pass a comma separated list in the cve parameter to fetch many at once. Adding scope equals time-series returns a time-series array on each result with the earlier daily values. In my sample, the history showed the score barely moving for one CVE over several days, which is the kind of stability you can use when deciding how often to refresh.
Paging, limits and politeness
The FIRST API documentation sets global parameters for paging and output: limit, between 0 and 10,000, offset starting at 0, sort, fields to trim the response, and envelope. It also states that public endpoints without authentication are limited to 1,000 requests per minute, that exceeding it returns a 429 error with a temporary block, and that you should use a sensible limit and avoid concurrent requests when pulling large datasets.
Practical steps:
- Batch CVE IDs in each request.
- Cache by CVE and date, and refresh daily at most.
- Respect a 429 by backing off, not by retrying at once.
- Use the fields parameter if you only need some columns.
- Do not run concurrent loops against the endpoint.
How to use the score
EPSS answers one question. It does not know your environment, your exposure or whether your code calls the vulnerable function. Use it with known exploitation data such as the CISA catalog, and with reachability. Treat a high percentile as a reason to look sooner, and a low one as a reason not to panic, not as a reason to ignore.
Also store the date with every score. A number without a date is hard to defend in an audit.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how likelihood and impact combine into a priority.
Where this fits
See how to add up EPSS scores into an expected exploited count. Safeguard offers reachability analysis and dependency scanning, and the free scan is a quick way to try it.
Quick check
Is EPSS a severity score?
No. It estimates the probability of exploitation. Severity systems such as CVSS describe impact.
Are the EPSS values numbers in the JSON?
In the response I fetched, epss and percentile were quoted strings. Convert them before comparing.
Sources
Last reviewed: 19 October 2026.