<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Epss V5 | FirewallSync</title><link>https://firewallsync.com/tags/epss-v5/</link><description>Practical cybersecurity writing for engineering teams that ship fast.</description><language>en-us</language><image><url>https://firewallsync.com/icon-512.png</url><title>FirewallSync</title><link>https://firewallsync.com/</link></image><lastBuildDate>Fri, 06 Nov 2026 04:45:00 +0000</lastBuildDate><atom:link href="https://firewallsync.com/tags/epss-v5/index.xml" rel="self" type="application/rss+xml"/><item><title>EPSS v5: How Scores Shifted and What to Re-baseline</title><link>https://firewallsync.com/posts/epss-v5-score-shift-model-version-v2026-06-15/</link><guid>https://firewallsync.com/posts/epss-v5-score-shift-model-version-v2026-06-15/</guid><pubDate>Fri, 06 Nov 2026 04:45:00 +0000</pubDate><dc:creator>John Marshall</dc:creator><category>Security Operations</category><description>EPSS v5 (model v2026.06.15) replaced v4 in the daily feed on June 15, 2026. We diffed the last v4 file against the first v5 file: 26% fewer CVEs at or above 0.1, 41% fewer at or above 0.5, a median score almost three times higher, and only 588 of the top 1,000 CVEs unchanged. Here is what that means for threshold rules, and a tested guard that stops your pipeline on the next model change.</description><enclosure url="https://firewallsync.com/posts/epss-v5-score-shift-model-version-v2026-06-15/cover_hu8687825451073364504.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/epss-v5-score-shift-model-version-v2026-06-15/cover_hu8687825451073364504.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/epss-v5-score-shift-model-version-v2026-06-15/cover_hu8687825451073364504.jpg" alt="Close-up of an oval dial thermometer whose glass is covered in ice crystals, with a red needle visible beneath the frost" width="1200" height="630"></p><p>The EPSS daily file changed models on <strong>June 15, 2026</strong>. The first line of the June 14 file reads <code>#model_version:v2025.03.14</code> (v4). The June 15 file reads <code>#model_version:v2026.06.15</code> (v5). We compared those two files, which together hold 340,204 CVEs scored on both days. If your pipeline gates on a fixed EPSS probability, it lost about a quarter of its flagged CVEs overnight: <strong>23,069 CVEs scored 0.1 or higher under v4 and 17,041 under v5</strong>. Nothing about those vulnerabilities changed that day; the model did.</p>
<p>This article covers what changed in v5, what the shift looks like in the data, and what to re-baseline. For the file format itself (columns, header line, how to join it to a scanner export), see our <a href="/posts/epss-data-feed-columns-percentile-vs-probability-and-how-to-join-it-to-a-scanner-export/">EPSS data feed guide</a>. That guide already lists the five model versions and their start dates; this one measures the most recent change.</p>
<h2 id="what-changed-in-v5">What changed in v5</h2>
<p>Empirical Security, which runs the EPSS model and hosts the data, <a href="https://lifestyle.kbew98country.com/story/220743/empirical-security-releases-epss-v5/">announced EPSS V5 on May 13, 2026</a>. The release says v5 &ldquo;incorporates improved modeling techniques and optimization algorithms&rdquo; and that &ldquo;the calibration step has been refined.&rdquo; It also cites a better classifier for published exploit code and &ldquo;the addition of new data feeds.&rdquo;</p>
<p>The headline claim is a 23% improvement. Empirical&rsquo;s <a href="https://research.empiricalsecurity.com/research/epss-v5-is-here">research post</a> defines the metric only loosely, as one that rewards &ldquo;ranking genuinely exploited vulnerabilities above ones that pose no real threat.&rdquo; On data from May 4, 2026, it reports that v4 scored 0.514 and v5 scored 0.633, where &ldquo;a random guess would score around 0.025, and a perfect model would score 1.0.&rdquo; We did not reproduce that evaluation.</p>
<p>The rollout is visible in the public <a href="https://github.com/empiricalsec/epss_scores">empiricalsec/epss_scores</a> repository:</p>
<table>
  <thead>
      <tr>
          <th>Date</th>
          <th>What the repository shows</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>2026-05-22 to 2026-06-08</td>
          <td><code>beta_scores/epssv5_beta-*.csv.gz</code>, header <code>#model_version:v2026.05.12</code></td>
      </tr>
      <tr>
          <td>2026-06-14</td>
          <td>Last daily file on <code>v2025.03.14</code> (v4), <code>score_date</code> 12:55:00Z</td>
      </tr>
      <tr>
          <td>2026-06-15</td>
          <td>First daily file on <code>v2026.06.15</code> (v5), <code>score_date</code> 12:03:41Z</td>
      </tr>
      <tr>
          <td>2026-11-05</td>
          <td>Still <code>v2026.06.15</code></td>
      </tr>
  </tbody>
</table>
<p>The beta files carry a different model label (<code>v2026.05.12</code>) from the production model, so treat beta scores as a preview of v5, not as v5 itself. The repository README lists the model changes for v2, v3 and v4 but, as of November 6, 2026, has no v5 entry. The file header was the reliable signal.</p>
<p>The CSV format did not change. Both files have the same comment line followed by <code>cve,epss,percentile</code>.</p>
<h2 id="how-the-scores-moved">How the scores moved</h2>
<p>We loaded <code>2026/epss_scores-2026-06-14.csv.gz</code> and <code>2026/epss_scores-2026-06-15.csv.gz</code> from the repository and compared CVEs present in both. For a baseline, we ran the same comparison on June 13 and June 14, two consecutive v4 days.</p>
<table>
  <thead>
      <tr>
          <th>Measure</th>
          <th>v4 (June 14)</th>
          <th>v5 (June 15)</th>
          <th>Normal day (June 13 to 14)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CVEs scored</td>
          <td>341,350</td>
          <td>340,247</td>
          <td>341,309 to 341,350</td>
      </tr>
      <tr>
          <td>Median EPSS</td>
          <td>0.00262</td>
          <td>0.00751</td>
          <td>unchanged</td>
      </tr>
      <tr>
          <td>Mean EPSS</td>
          <td>0.03328</td>
          <td>0.02934</td>
          <td>unchanged</td>
      </tr>
      <tr>
          <td>99th percentile of EPSS</td>
          <td>0.77230</td>
          <td>0.59470</td>
          <td>n/a</td>
      </tr>
      <tr>
          <td>CVEs at or above 0.1</td>
          <td>23,069</td>
          <td>17,041</td>
          <td>23,071 to 23,069</td>
      </tr>
      <tr>
          <td>CVEs at or above 0.5</td>
          <td>7,193</td>
          <td>4,249</td>
          <td>7,194 to 7,193</td>
      </tr>
      <tr>
          <td>Crossed 0.1 upward / downward</td>
          <td>3,820 / 9,847</td>
          <td></td>
          <td>9 / 11</td>
      </tr>
      <tr>
          <td>Crossed the 90th percentile in / out</td>
          <td>9,837 / 9,944</td>
          <td></td>
          <td>25 / 29</td>
      </tr>
      <tr>
          <td>Moved by 2x or more</td>
          <td>243,259 of 340,204 (71.5%)</td>
          <td></td>
          <td>313 of 341,309</td>
      </tr>
      <tr>
          <td>Top 1,000 by EPSS that stayed top 1,000</td>
          <td>588</td>
          <td></td>
          <td>999</td>
      </tr>
  </tbody>
</table>
<p>Three patterns stand out.</p>
<p><strong>The distribution got narrower.</strong> The lowest v4 score was 0.00001 and 93,484 CVEs sat below 0.001. Under v5 the minimum is 0.00046 and only 3,552 CVEs are below 0.001. At the top end, the 99th percentile fell from 0.772 to 0.595. The median ratio of v5 to v4 score was 2.89: most low-scored CVEs went up, while many of the high scorers came down. That fits the release&rsquo;s description of recalibration, but the release does not say this is the intended effect, so treat it as our reading of the data.</p>
<p><strong>Fixed cutoffs shrank.</strong> A rule like <code>epss &gt;= 0.1</code> matched 26.1% fewer CVEs the day v5 went live, and <code>epss &gt;= 0.5</code> matched 40.9% fewer. Of the CVEs that crossed 0.1, 9,847 dropped below it and only 3,820 rose above it.</p>
<p><strong>Percentile rules kept their size, not their members.</strong> A percentile is a rank, so the 90th-percentile bucket stays about 10% of scored CVEs. But 9,837 CVEs entered it and 9,944 left it in one day, compared with 25 and 29 on a normal v4 day. If you track &ldquo;new CVEs in the top decile&rdquo; as a work queue, June 15 would have looked like a flood.</p>
<p>1,146 CVEs scored on June 14 were missing from the June 15 file and 43 appeared for the first time. By November 5, all but 119 of the missing ones were back in the feed. We did not establish why they were absent that day.</p>
<h2 id="what-happened-to-kev-listed-cves">What happened to KEV-listed CVEs</h2>
<p>To see whether v5 demoted known-exploited vulnerabilities, we took the <a href="https://github.com/cisagov/kev-data">CISA KEV catalog</a> (catalog version 2026.11.04) and kept only the 1,619 entries whose <code>dateAdded</code> is on or before June 14, 2026, so the set matches what was known on the switch date. All 1,619 were scored on both days.</p>
<table>
  <thead>
      <tr>
          <th>KEV CVEs (added by 2026-06-14)</th>
          <th>v4</th>
          <th>v5</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Median EPSS</td>
          <td>0.704</td>
          <td>0.535</td>
      </tr>
      <tr>
          <td>At or above 0.1</td>
          <td>1,224</td>
          <td>1,219</td>
      </tr>
      <tr>
          <td>At or above the 90th percentile</td>
          <td>1,323</td>
          <td>1,366</td>
      </tr>
  </tbody>
</table>
<p>The probability for KEV entries came down along with the rest of the high end. But almost the same number cleared 0.1, and more of them landed in the top decile. KEV-listed CVEs that a 0.1 rule already caught were still caught. A rule set to 0.5 or 0.7 on the assumption that KEV CVEs sit there would have lost many of them, since the median is now about 0.54.</p>
<p>This is one reason KEV should stay a separate input instead of being folded into an EPSS cutoff. Our <a href="/posts/cvss-vs-epss-vs-kev-which-signal-should-decide-what-you-patch-first/">CVSS vs EPSS vs KEV comparison</a> covers why; the <a href="/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/">prioritization workflow</a> shows where each signal sits in the patch decision.</p>
<h2 id="what-to-re-baseline">What to re-baseline</h2>
<p>These are our recommendations, based on the data above. We have not measured their effect on any team&rsquo;s backlog.</p>
<ol>
<li><strong>Find every fixed probability cutoff.</strong> SLA rules, ticket triggers, dashboard colours and scanner policies. If one was tuned against v4 data, check how many CVEs it matches today versus before June 15.</li>
<li><strong>Decide what the cutoff is for.</strong> If it sizes a queue (&ldquo;the top few thousand CVEs&rdquo;), switch it to a percentile. If it expresses risk (&ldquo;at least a 10% chance of exploitation in 30 days&rdquo;), keep the probability, because v5&rsquo;s calibration is meant to make that reading more accurate, but accept that the queue size will move.</li>
<li><strong>Do not compare scores across the switch.</strong> A CVE that went from 0.4 to 0.2 on June 15 did not become less likely to be exploited that day. If you chart EPSS history, mark June 15, 2026 (and the earlier switches on 2022-02-04, 2023-03-07 and 2025-03-17).</li>
<li><strong>Keep KEV as an override.</strong> Do not rely on EPSS to bring KEV entries above a high cutoff.</li>
<li><strong>Store <code>model_version</code> next to every score.</strong> Then you can always tell which model produced a score your system acted on.</li>
</ol>
<h2 id="a-guard-for-the-next-model-change">A guard for the next model change</h2>
<p>There is no API callback when the model changes, but the file tells you. This script compares the header of yesterday&rsquo;s and today&rsquo;s file and exits non-zero on a model change, so a CI job or cron wrapper can stop before ingesting.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;Stop an EPSS ingest when the model version changes.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Usage: python3 epss_model_guard.py yesterday.csv.gz today.csv.gz&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> gzip<span style="color:#f92672">,</span> sys
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">header</span>(path):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">with</span> gzip<span style="color:#f92672">.</span>open(path, <span style="color:#e6db74">&#34;rt&#34;</span>) <span style="color:#66d9ef">as</span> f:
</span></span><span style="display:flex;"><span>        first <span style="color:#f92672">=</span> f<span style="color:#f92672">.</span>readline()<span style="color:#f92672">.</span>strip()
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">not</span> first<span style="color:#f92672">.</span>startswith(<span style="color:#e6db74">&#34;#&#34;</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> {<span style="color:#e6db74">&#34;model_version&#34;</span>: <span style="color:#e6db74">&#34;pre-v2 (no header)&#34;</span>, <span style="color:#e6db74">&#34;score_date&#34;</span>: <span style="color:#e6db74">&#34;&#34;</span>}
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> dict(kv<span style="color:#f92672">.</span>split(<span style="color:#e6db74">&#34;:&#34;</span>, <span style="color:#ae81ff">1</span>) <span style="color:#66d9ef">for</span> kv <span style="color:#f92672">in</span> first<span style="color:#f92672">.</span>lstrip(<span style="color:#e6db74">&#34;#&#34;</span>)<span style="color:#f92672">.</span>split(<span style="color:#e6db74">&#34;,&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>old, new <span style="color:#f92672">=</span> header(sys<span style="color:#f92672">.</span>argv[<span style="color:#ae81ff">1</span>]), header(sys<span style="color:#f92672">.</span>argv[<span style="color:#ae81ff">2</span>])
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;previous: </span><span style="color:#e6db74">{</span>old[<span style="color:#e6db74">&#39;model_version&#39;</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74"> scored </span><span style="color:#e6db74">{</span>old[<span style="color:#e6db74">&#39;score_date&#39;</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;current:  </span><span style="color:#e6db74">{</span>new[<span style="color:#e6db74">&#39;model_version&#39;</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74"> scored </span><span style="color:#e6db74">{</span>new[<span style="color:#e6db74">&#39;score_date&#39;</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> old[<span style="color:#e6db74">&#34;model_version&#34;</span>] <span style="color:#f92672">!=</span> new[<span style="color:#e6db74">&#34;model_version&#34;</span>]:
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#34;MODEL CHANGE: hold threshold-based alerts and re-baseline before ingesting&#34;</span>)
</span></span><span style="display:flex;"><span>    sys<span style="color:#f92672">.</span>exit(<span style="color:#ae81ff">2</span>)
</span></span></code></pre></div><p>We ran it with Python 3 against files from the repository:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>$ python3 epss_model_guard.py epss_scores-2026-06-14.csv.gz epss_scores-2026-06-15.csv.gz
</span></span><span style="display:flex;"><span>previous: v2025.03.14 scored 2026-06-14T12:55:00Z
</span></span><span style="display:flex;"><span>current:  v2026.06.15 scored 2026-06-15T12:03:41Z
</span></span><span style="display:flex;"><span>MODEL CHANGE: hold threshold-based alerts and re-baseline before ingesting
</span></span><span style="display:flex;"><span>exit=2
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ python3 epss_model_guard.py epss_scores-2026-11-04.csv.gz epss_scores-2026-11-05.csv.gz
</span></span><span style="display:flex;"><span>previous: v2026.06.15 scored 2026-11-04T12:03:12Z
</span></span><span style="display:flex;"><span>current:  v2026.06.15 scored 2026-11-05T12:03:04Z
</span></span><span style="display:flex;"><span>exit=0
</span></span></code></pre></div><p>When the guard trips, run the same comparison we did above (counts at your cutoffs, percentile churn, KEV coverage) before you turn alerts back on. Note the <code>score_date</code> format also changed with v4 (from <code>+0000</code> offsets to <code>Z</code>), so parse it as ISO 8601 instead of matching a fixed string.</p>
<h2 id="limits-of-this-article">Limits of this article</h2>
<ul>
<li>We compared one pair of days. Scores on later v5 days have kept moving as new signals arrive, so today&rsquo;s counts differ from June 15.</li>
<li>The 23% improvement figure and the description of model changes come from Empirical Security. We did not test model accuracy.</li>
<li>KEV is a list of vulnerabilities known to be exploited, not a ground truth for EPSS&rsquo;s 30-day prediction window, so the KEV table shows coverage, not accuracy.</li>
<li>We did not find a FIRST page describing v5 in the sources we could reach. If FIRST publishes a different start date or model description, the file headers above are still what your pipeline will see.</li>
</ul>
<h2 id="sources-and-verification">Sources and verification</h2>
<table>
  <thead>
      <tr>
          <th>Important claim</th>
          <th>Source</th>
          <th>Status</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Model version and score date of each daily and beta file; all score counts, medians, percentiles and crossings</td>
          <td><a href="https://github.com/empiricalsec/epss_scores">empiricalsec/epss_scores</a> files for 2026-06-13, 06-14, 06-15, 11-04, 11-05 and <code>beta_scores/</code>, computed with Python</td>
          <td>Verified (computed)</td>
      </tr>
      <tr>
          <td>README lists v2, v3 and v4 start dates and no v5 entry</td>
          <td><a href="https://github.com/empiricalsec/epss_scores">epss_scores README</a></td>
          <td>Verified, Nov 6, 2026</td>
      </tr>
      <tr>
          <td>v5 announced May 13, 2026; modeling, calibration, exploit-code classifier and data-feed changes; 23% improvement</td>
          <td><a href="https://lifestyle.kbew98country.com/story/220743/empirical-security-releases-epss-v5/">Empirical Security press release</a></td>
          <td>Verified (vendor claim)</td>
      </tr>
      <tr>
          <td>v4 scored 0.514 and v5 0.633 on May 4, 2026 data; random about 0.025</td>
          <td><a href="https://research.empiricalsecurity.com/research/epss-v5-is-here">EPSS V5 Is Here</a></td>
          <td>Qualified: metric not fully specified</td>
      </tr>
      <tr>
          <td>KEV entries added by 2026-06-14 (1,619) and their scores</td>
          <td><a href="https://github.com/cisagov/kev-data">cisagov/kev-data</a>, catalog 2026.11.04, joined to the EPSS files</td>
          <td>Verified (computed)</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item></channel></rss>