Safeguard
Industry Analysis•

Can two CVEs have the same EPSS score but different percentiles?

Yes. In the 18 October 2026 EPSS file, 1,142 CVEs shared one score yet had percentiles spread across about 0.3 points. Use probability for cutoffs.

Safeguard Security Team
6 min read

Yes. In the EPSS file scored on 18 October 2026, 1,142 CVEs shared the identical probability 0.00266, yet their percentile values ran from 0.17226 to 0.17518. A percentile cutoff can therefore split tied CVEs. Cut on probability when you need a rule that treats equal scores equally.

What the data shows

The author read the file (390,807 rows, model v2026.06.15) and counted distinct probability values. There were 22,625 distinct scores, and the most common, 0.00266, appeared on 1,142 CVEs. That is about 0.29 percent of all rows sharing one number.

Those 1,142 rows did not share a percentile. The values spanned 0.17226 to 0.17518, a spread of 0.00292, which is exactly 1,142 divided by 390,807. In other words, the percentile numbers inside a tie are spread out one rank at a time, so tied CVEs get a ladder of distinct percentiles.

Scores in the file have five decimal places. At the low end, where most CVEs sit, that precision runs out and many rows tie.

Why this matters for a shortlist

Say your rule is "take everything in the top 1 percent by percentile". Arithmetic on this file says that is roughly 3,908 rows. If the 3,908th row falls in the middle of a tie, rows with the same probability are on opposite sides of your line. Ties are most common at the low end, where most CVEs sit, so any cutoff drawn there is the least reliable. Check your own file before trusting a line near the top as well.

A probability threshold avoids this: everything at or above 0.1 is in, everything below is out. In the same file, 17,321 rows (4.4 percent) scored 0.1 or higher. For choosing a threshold, see how to choose an EPSS threshold.

How to check for ties in your own data

import csv, collections
rows = [r for r in csv.DictReader(l for l in open("epss.csv") if not l.startswith("#"))]
c = collections.Counter(r["epss"] for r in rows)
print(len(c), c.most_common(3))

Then, for the most common score, list the min and max percentile among its rows. If they differ, you have tied probabilities with distinct percentiles.

Rules of thumb

  1. Do not treat a small percentile difference inside a tie as meaningful.
  2. Prefer probability for filters and thresholds. FIRST's guidance is that a single reported score should be the probability.
  3. Use percentile for context, as in "15.3% (92nd)".
  4. State the file date. Both values change daily.
  5. Report ties if you report a "top n" list. Say how you broke them, such as by CVE ID.

A worked example with the real tie

The most common score in the 18 October file was 0.00266. It appeared on 1,142 CVEs. If you sort those rows by percentile, they run from 0.17226 to 0.17518 in steps of 0.00001, one step for each CVE. So the first CVE in the tie has a percentile of about 17.2 percent and the last about 17.5 percent, yet all 1,142 have the same chance estimate.

Now suppose a report says "we reviewed everything above the 17.4th percentile". That cutoff falls inside the tie, so some CVEs with probability 0.00266 are in the review set and others with the same probability are not. Nothing in the data justifies that split. A probability rule such as "review everything at 0.003 or above" would put all tied CVEs on the same side.

Why the file does it this way

A percentile needs a rank for every row, and ranks are distinct even when scores tie. The author did not find a documented tie breaking rule on the pages fetched, so treat the order within a tie as arbitrary for analysis. If you need a stable order, break ties yourself and say how, for example by CVE ID.

A table of choices

GoalUseWhy
Hard cutoff for a work queueProbability thresholdEqual scores get equal treatment
Context in a reportPercentile beside probabilityShows where the score sits
Top n listProbability, ties broken by CVE IDStable and explainable
Trend over timeProbability with model versionPercentile shifts as the population changes

FIRST's guidance is that a single reported EPSS value should be the probability, and showing both is better, for example "15.3% (92nd)".

Steps to test your own shortlist

  1. Load the file and sort by probability.
  2. Find the row where your cutoff falls.
  3. Check whether the rows just above and below have the same probability.
  4. If they do, move the cutoff to the nearest score boundary and record the new count.
  5. Re-run on the next day's file, since boundaries move.

This check takes a couple of minutes and avoids a defensible-looking but arbitrary rule. It also makes your count reproducible: anyone with the same file and the same threshold will get the same list.

Ties and combined signals

When you combine EPSS with other signals, such as KEV listing or reachability, ties become less important, because the second signal separates the rows. The cutoff question matters most when EPSS is your only filter. For a combined approach, see one funnel for prioritization metrics.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how a second signal separates findings that one score cannot.

Quick check

Is the percentile order inside a tie meaningful?

No. The CVEs have the same probability, so the order among them carries no extra information.

Should I stop using percentile?

No. It is useful context. Just avoid hard cutoffs on it when ties are likely.

How many decimal places does the file give?

Five, in the 18 October file. That precision runs out at the low end, where many CVEs share a value.

Sources

Last reviewed: 19 October 2026.

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.