<?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>Ssvc | FirewallSync</title><link>https://firewallsync.com/tags/ssvc/</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>Tue, 03 Nov 2026 04:30:00 +0000</lastBuildDate><atom:link href="https://firewallsync.com/tags/ssvc/index.xml" rel="self" type="application/rss+xml"/><item><title>CVE ADP Containers: CISA-ADP, CVE Program and Supplier ADPs</title><link>https://firewallsync.com/posts/cve-adp-containers-cisa-adp-cve-program-supplier-sadp/</link><guid>https://firewallsync.com/posts/cve-adp-containers-cisa-adp-cve-program-supplier-sadp/</guid><pubDate>Tue, 03 Nov 2026 04:30:00 +0000</pubDate><dc:creator>John Marshall</dc:creator><category>Security Operations</category><description>A CVE record has one CNA container and possibly several ADP containers. Here is what CISA-ADP, the CVE Program Container and supplier ADPs such as redhat-SADP and siemens-SADP add, how often each appears in a sample of 2,000 2026 records, and a tested script that shows who said what.</description><enclosure url="https://firewallsync.com/posts/cve-adp-containers-cisa-adp-cve-program-supplier-sadp/cover_hu6338534624026322280.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/cve-adp-containers-cisa-adp-cve-program-supplier-sadp/cover_hu6338534624026322280.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/cve-adp-containers-cisa-adp-cve-program-supplier-sadp/cover_hu6338534624026322280.jpg" alt="Grid of dark wooden card catalog drawers, each with a brass label holder showing an alphabetical range and a brass pull" width="1200" height="630"></p><p><strong>Scope.</strong> This is a specification explainer with measurements from public data. We read the CVE JSON schema (<code>CVE_Record_Format.json</code>, default <code>dataVersion</code> 5.2.0, CVEProject/cve-schema main branch), the cvelistV5 README and the CISA Vulnrichment README, then sampled 2,000 random 2026 record files from cvelistV5 at commit <code>1a44d59</code> (November 3, 2026). The script below was run with Python 3.13.</p>
<h2 id="the-short-answer">The short answer</h2>
<p>A CVE record is not one author&rsquo;s statement. Under <code>containers</code> there is exactly one <code>cna</code> object, written by the CVE Numbering Authority that assigned the ID, and an optional <code>adp</code> array. Each <code>adp</code> entry is written by an Authorized Data Publisher and names its author in <code>providerMetadata.shortName</code>.</p>
<p>In 2026 records you will mostly meet three kinds:</p>
<table>
  <thead>
      <tr>
          <th><code>shortName</code></th>
          <th>Title in the container</th>
          <th>What it adds</th>
          <th>Share of 1,963 published records in our sample</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>CISA-ADP</code></td>
          <td>CISA ADP Vulnrichment</td>
          <td>SSVC decision points; sometimes CVSS, CWE, KEV date</td>
          <td>93.9%</td>
      </tr>
      <tr>
          <td><code>CVE</code></td>
          <td>CVE Program Container</td>
          <td>References added by the CVE Program</td>
          <td>2.2%</td>
      </tr>
      <tr>
          <td><code>redhat-SADP</code>, <code>siemens-SADP</code></td>
          <td>Supplier&rsquo;s own titles (or none)</td>
          <td>The supplier&rsquo;s affected products, versions, fixes, severity</td>
          <td>1.2% combined</td>
      </tr>
  </tbody>
</table>
<p>The rule that matters for tooling: read the CNA container and the CVE Program Container every time, read CISA-ADP for prioritization signals, and treat supplier ADPs as extra affected-product data for that supplier&rsquo;s builds. Keep every value tagged with who published it.</p>
<h2 id="what-the-schema-says-about-adp-containers">What the schema says about ADP containers</h2>
<p>The schema describes <code>containers</code> as &ldquo;a set of structures (called containers) used to store vulnerability information related to a specific CVE ID provided by a specific organization participating in the CVE program.&rdquo; It goes on: &ldquo;There can only be one &lsquo;cna&rsquo; container, as there can only be one assigning CNA. However, there can be multiple &lsquo;adp&rsquo; containers.&rdquo;</p>
<p>Three details shape how you parse them:</p>
<ul>
<li><strong>Only <code>providerMetadata</code> is required.</strong> The <code>adpContainer</code> definition lists <code>providerMetadata</code> as required with <code>minProperties: 2</code>, so an ADP container can be just a publisher plus one other field. Code that assumes <code>affected</code>, <code>descriptions</code> or <code>metrics</code> will exist breaks.</li>
<li><strong>The fields mirror the CNA container.</strong> An ADP container can carry <code>affected</code>, <code>cpeApplicability</code>, <code>problemTypes</code>, <code>metrics</code>, <code>references</code>, <code>solutions</code>, <code>workarounds</code>, <code>exploits</code>, <code>timeline</code> and more. The schema notes that &ldquo;for the most part, the &lsquo;cna&rsquo; and &lsquo;adp&rsquo; containers contain the same properties. The main differences are the source of the information.&rdquo;</li>
<li><strong>Extensions are allowed.</strong> <code>adpContainer</code> permits properties matching <code>^x_[^.]*$</code>. Supplier ADPs use this: every redhat-SADP and siemens-SADP container in our sample had <code>&quot;x_adpType&quot;: &quot;supplier&quot;</code>, and Red Hat&rsquo;s also carried <code>x_generator</code>. These are not schema-defined fields, so treat them as hints.</li>
</ul>
<p><code>providerMetadata</code> holds <code>orgId</code> (a UUID, required), <code>shortName</code> and <code>dateUpdated</code>. Match publishers on <code>orgId</code> if you need certainty; <code>shortName</code> is what humans read.</p>
<h2 id="the-three-kinds-you-will-see">The three kinds you will see</h2>
<h3 id="cisa-adp-prioritization-signals">CISA-ADP: prioritization signals</h3>
<p>The cvelistV5 README says the CISA ADP provides three things: SSVC, KEV catalog data, and &ldquo;Vulnrichment&rdquo; updates such as &ldquo;missing CVSS, CWE, CPE information for CVE Records that meet specific threat characteristics, and for when CNAs do not provide it themselves.&rdquo;</p>
<p>What that looked like in our sample of 1,963 published records:</p>
<table>
  <thead>
      <tr>
          <th>CISA-ADP content</th>
          <th>Records</th>
          <th>Share of published</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>SSVC block (<code>metrics[].other.type = &quot;ssvc&quot;</code>)</td>
          <td>1,844</td>
          <td>93.9%</td>
      </tr>
      <tr>
          <td>CVSS (v3.1 in all but one)</td>
          <td>389</td>
          <td>19.8%</td>
      </tr>
      <tr>
          <td>CWE in <code>problemTypes</code></td>
          <td>336</td>
          <td>17.1%</td>
      </tr>
      <tr>
          <td>KEV block (<code>metrics[].other.type = &quot;kev&quot;</code>)</td>
          <td>5</td>
          <td>0.3%</td>
      </tr>
  </tbody>
</table>
<p>Every CISA-ADP container in the sample carried SSVC. CVSS and CWE were mostly gap-fills: 381 of the 389 CVSS entries (97.9%) and 326 of the 336 CWE entries (97.0%) sat on records whose CNA container had none. That matches the Vulnrichment README: &ldquo;For those CVEs that do not already have these fields populated by the originating CNA, CISA will populate the associated ADP container with those values when there is enough supporting evidence to do so. At no point will CISA overwrite the originating CNA&rsquo;s data in the original CNA container.&rdquo;</p>
<p>The exceptions matter. In 8 records both the CNA and CISA-ADP carried a CVSS score, and they did not always agree: in CVE-2026-70373 the CNA (TuranSec) published <code>CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H</code> (8.8) while CISA-ADP published <code>.../C:H/I:N/A:N</code> (6.5). We did not check which came first. The point is that a parser which picks &ldquo;the first CVSS it finds&rdquo; will produce different answers depending on container order.</p>
<p>The KEV block is small: <code>dateAdded</code> and a link to the catalog. Treat it as a pointer, and use the KEV catalog itself for <code>dueDate</code>, <code>requiredAction</code> and ransomware use. Our <a href="/posts/cisa-kev-json-feed-what-each-field-means-and-how-to-match-it-against-a-scanner-export/">KEV JSON feed field guide</a> covers those fields, and the <a href="/posts/cisa-vulnrichment-how-to-read-ssvc-values-in-a-cve-record-and-turn-them-into-a-patch-decision/">Vulnrichment SSVC guide</a> covers the three SSVC values.</p>
<h3 id="the-cve-program-container-references-you-must-not-skip">The CVE Program Container: references you must not skip</h3>
<p>The cvelistV5 README is explicit. The container has title &ldquo;CVE Program Container&rdquo; and <code>shortName</code> &ldquo;CVE&rdquo;, and &ldquo;all CVE Program-added references after 7/31/2024 for a CVE Record will be stored in the CVE Program Container of that Record. CNA-provided references will continue to be stored in the CNA Container.&rdquo;</p>
<p>It also says what tools must do: &ldquo;to retrieve all information about a reported vulnerability in the CVE Repository, tool vendors and community users will need to examine the CVE Record CNA Container and the CVE Program Container (if one exists). These two containers are minimally required to obtain the core information required by the Program. All other ADP containers remain optional from a Program perspective.&rdquo;</p>
<p>Two practical consequences:</p>
<ul>
<li>References tagged <code>x_transferred</code> were copied from the CNA container on July 31, 2024, so expect duplicates. The README says downstream users &ldquo;will have to determine the appropriate way to resolve potential reference duplications.&rdquo; Deduplicate on URL.</li>
<li>New records only get this container if the Program adds something. In our 2026 sample, 43 records (2.2%) had one.</li>
</ul>
<h3 id="supplier-adps-a-vendors-view-of-someone-elses-cve">Supplier ADPs: a vendor&rsquo;s view of someone else&rsquo;s CVE</h3>
<p>Supplier ADP containers let a vendor that ships an upstream component add its own product data to a CVE that a different CNA assigned. Siemens describes its SADP as useful when &ldquo;a supplier like Siemens wants to add information to a vulnerability&rdquo; in an upstream dependency, and says it was introduced in April 2026 after a pilot. Its stated aim is better scanner matching for affected Siemens products, with &ldquo;known-not-affected&rdquo; product data planned later.</p>
<p>In our sample, 24 published records (1.2%) carried one: 18 from <code>redhat-SADP</code>, 6 from <code>siemens-SADP</code>. Their shapes differ:</p>
<ul>
<li><strong>redhat-SADP</strong> containers looked like a full advisory: <code>affected</code> entries per Red Hat product stream with CPEs, package names and RPM <code>versionType</code>, plus Red Hat&rsquo;s severity rating, CVSS, <code>solutions</code>, <code>workarounds</code> and references.</li>
<li><strong>siemens-SADP</strong> containers were lean: <code>affected</code> entries for Siemens products, references to the Siemens advisory, and nothing else. All had <code>defaultStatus</code> set to <code>unknown</code>.</li>
</ul>
<p>Two traps. First, supplier <code>affected</code> data describes the supplier&rsquo;s product names and version strings, not the upstream project&rsquo;s. A Red Hat entry such as <code>defaultStatus: affected</code> with <code>lessThan: &quot;*&quot;</code> and <code>status: unaffected</code> from a fixed RPM version is a statement about that Red Hat package, which is how our <a href="/posts/cve-affected-versions-lessthan-defaultstatus-versiontype/">affected-versions guide</a> explains these encodings. Second, supplier severity ratings and CVSS are the supplier&rsquo;s assessment for its builds and can legitimately differ from the CNA&rsquo;s.</p>
<h2 id="one-record-four-publishers">One record, four publishers</h2>
<p>CVE-2026-46300 is a Linux kernel flaw assigned by the <code>Linux</code> CNA and added to the KEV catalog on October 28, 2026. Its record shows why you need a per-provider view. This is the output of the script in the next section against the cvelistV5 file at commit <code>1a44d59</code>:</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>CVE-2026-46300 PUBLISHED dataVersion 5.2
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[cna] Linux (updated 2026-08-05)
</span></span><span style="display:flex;"><span>  cvss: [&#39;3.1 7.8 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H&#39;]
</span></span><span style="display:flex;"><span>  affected_products: 2
</span></span><span style="display:flex;"><span>  references: 8
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[adp] CVE (updated 2026-05-23)
</span></span><span style="display:flex;"><span>  references: 4
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[adp] redhat-SADP (updated 2026-09-01)
</span></span><span style="display:flex;"><span>  other: [&#39;Red Hat severity rating: Important&#39;]
</span></span><span style="display:flex;"><span>  cvss: [&#39;3.1 7.8 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H&#39;]
</span></span><span style="display:flex;"><span>  cwe: [&#39;CWE-123&#39;]
</span></span><span style="display:flex;"><span>  affected_products: 39
</span></span><span style="display:flex;"><span>  references: 36
</span></span><span style="display:flex;"><span>  solutions: 33
</span></span><span style="display:flex;"><span>  workarounds: 1
</span></span><span style="display:flex;"><span>  x_adpType: supplier
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[adp] siemens-SADP (updated 2026-10-15)
</span></span><span style="display:flex;"><span>  affected_products: 10
</span></span><span style="display:flex;"><span>  references: 2
</span></span><span style="display:flex;"><span>  x_adpType: supplier
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[adp] CISA-ADP (updated 2026-10-29)
</span></span><span style="display:flex;"><span>  ssvc: Exploitation=active, Automatable=no, Technical Impact=total
</span></span><span style="display:flex;"><span>  kev: dateAdded=2026-10-28
</span></span><span style="display:flex;"><span>  cwe: [&#39;CWE-456&#39;]
</span></span><span style="display:flex;"><span>  references: 1
</span></span></code></pre></div><p>Read it as five separate statements:</p>
<ul>
<li>The <strong>CNA</strong> says what the kernel project considers affected and scores it 7.8. It gives no CWE.</li>
<li>The <strong>CVE Program</strong> added four references a tool reading only the CNA container would miss.</li>
<li><strong>Red Hat</strong> lists 39 affected product entries for its own streams with 33 solutions, rates it Important, and maps it to CWE-123.</li>
<li><strong>Siemens</strong> lists 10 affected product entries for its own devices.</li>
<li><strong>CISA</strong> says exploitation is active, records the KEV date, and maps it to CWE-456, a different CWE from Red Hat&rsquo;s.</li>
</ul>
<p>None of these overrides the others. A kernel team, a RHEL fleet owner and an OT engineer running Siemens PLCs each need a different slice of the same record.</p>
<h2 id="a-tested-script-who-said-what">A tested script: who said what</h2>
<p>This Python script prints one block per container. It uses only the standard library and was run with Python 3.13 against the record above and against the 2,000-record sample.</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:#75715e">#!/usr/bin/env python3</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;Print who said what in a CVE JSON 5 record: one line per container and field.&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> json<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">summarize</span>(container):
</span></span><span style="display:flex;"><span>    out <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> m <span style="color:#f92672">in</span> container<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;metrics&#34;</span>, []):
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> k, v <span style="color:#f92672">in</span> m<span style="color:#f92672">.</span>items():
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">if</span> k<span style="color:#f92672">.</span>startswith(<span style="color:#e6db74">&#34;cvss&#34;</span>):
</span></span><span style="display:flex;"><span>                out<span style="color:#f92672">.</span>setdefault(<span style="color:#e6db74">&#34;cvss&#34;</span>, [])<span style="color:#f92672">.</span>append(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>v[<span style="color:#e6db74">&#39;version&#39;</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{</span>v[<span style="color:#e6db74">&#39;baseScore&#39;</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74"> </span><span style="color:#e6db74">{</span>v[<span style="color:#e6db74">&#39;vectorString&#39;</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">elif</span> k <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;other&#34;</span>:
</span></span><span style="display:flex;"><span>                t, c <span style="color:#f92672">=</span> v<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;type&#34;</span>), v<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;content&#34;</span>, {})
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">if</span> t <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;ssvc&#34;</span>:
</span></span><span style="display:flex;"><span>                    out[<span style="color:#e6db74">&#34;ssvc&#34;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;, &#34;</span><span style="color:#f92672">.</span>join(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>k2<span style="color:#e6db74">}</span><span style="color:#e6db74">=</span><span style="color:#e6db74">{</span>v2<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#66d9ef">for</span> o <span style="color:#f92672">in</span> c[<span style="color:#e6db74">&#34;options&#34;</span>] <span style="color:#66d9ef">for</span> k2, v2 <span style="color:#f92672">in</span> o<span style="color:#f92672">.</span>items())
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">elif</span> t <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;kev&#34;</span>:
</span></span><span style="display:flex;"><span>                    out[<span style="color:#e6db74">&#34;kev&#34;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;dateAdded=</span><span style="color:#e6db74">{</span>c<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;dateAdded&#39;</span>)<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">else</span>:
</span></span><span style="display:flex;"><span>                    out<span style="color:#f92672">.</span>setdefault(<span style="color:#e6db74">&#34;other&#34;</span>, [])<span style="color:#f92672">.</span>append(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>t<span style="color:#e6db74">}</span><span style="color:#e6db74">: </span><span style="color:#e6db74">{</span>c<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;value&#39;</span>, c)<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span>    cwes <span style="color:#f92672">=</span> [d[<span style="color:#e6db74">&#34;cweId&#34;</span>] <span style="color:#66d9ef">for</span> p <span style="color:#f92672">in</span> container<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;problemTypes&#34;</span>, []) <span style="color:#66d9ef">for</span> d <span style="color:#f92672">in</span> p<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;descriptions&#34;</span>, []) <span style="color:#66d9ef">if</span> d<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;cweId&#34;</span>)]
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> cwes: out[<span style="color:#e6db74">&#34;cwe&#34;</span>] <span style="color:#f92672">=</span> cwes
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> container<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;affected&#34;</span>): out[<span style="color:#e6db74">&#34;affected_products&#34;</span>] <span style="color:#f92672">=</span> len(container[<span style="color:#e6db74">&#34;affected&#34;</span>])
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> container<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;references&#34;</span>): out[<span style="color:#e6db74">&#34;references&#34;</span>] <span style="color:#f92672">=</span> len(container[<span style="color:#e6db74">&#34;references&#34;</span>])
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> k <span style="color:#f92672">in</span> (<span style="color:#e6db74">&#34;solutions&#34;</span>, <span style="color:#e6db74">&#34;workarounds&#34;</span>):
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> container<span style="color:#f92672">.</span>get(k): out[k] <span style="color:#f92672">=</span> len(container[k])
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#e6db74">&#34;x_adpType&#34;</span> <span style="color:#f92672">in</span> container: out[<span style="color:#e6db74">&#34;x_adpType&#34;</span>] <span style="color:#f92672">=</span> container[<span style="color:#e6db74">&#34;x_adpType&#34;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> out
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>rec <span style="color:#f92672">=</span> json<span style="color:#f92672">.</span>load(open(sys<span style="color:#f92672">.</span>argv[<span style="color:#ae81ff">1</span>]))
</span></span><span style="display:flex;"><span>c <span style="color:#f92672">=</span> rec[<span style="color:#e6db74">&#34;containers&#34;</span>]
</span></span><span style="display:flex;"><span>rows <span style="color:#f92672">=</span> [(<span style="color:#e6db74">&#34;cna&#34;</span>, c[<span style="color:#e6db74">&#34;cna&#34;</span>])] <span style="color:#f92672">+</span> [(<span style="color:#e6db74">&#34;adp&#34;</span>, a) <span style="color:#66d9ef">for</span> a <span style="color:#f92672">in</span> c<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;adp&#34;</span>, [])]
</span></span><span style="display:flex;"><span>print(rec[<span style="color:#e6db74">&#34;cveMetadata&#34;</span>][<span style="color:#e6db74">&#34;cveId&#34;</span>], rec[<span style="color:#e6db74">&#34;cveMetadata&#34;</span>][<span style="color:#e6db74">&#34;state&#34;</span>], <span style="color:#e6db74">&#34;dataVersion&#34;</span>, rec<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;dataVersion&#34;</span>))
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> kind, cont <span style="color:#f92672">in</span> rows:
</span></span><span style="display:flex;"><span>    pm <span style="color:#f92672">=</span> cont[<span style="color:#e6db74">&#34;providerMetadata&#34;</span>]
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">[</span><span style="color:#e6db74">{</span>kind<span style="color:#e6db74">}</span><span style="color:#e6db74">] </span><span style="color:#e6db74">{</span>pm<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;shortName&#39;</span>)<span style="color:#e6db74">}</span><span style="color:#e6db74"> (updated </span><span style="color:#e6db74">{</span>pm<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;dateUpdated&#39;</span>, <span style="color:#e6db74">&#39;?&#39;</span>)[:<span style="color:#ae81ff">10</span>]<span style="color:#e6db74">}</span><span style="color:#e6db74">)&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> k, v <span style="color:#f92672">in</span> summarize(cont)<span style="color:#f92672">.</span>items():
</span></span><span style="display:flex;"><span>        print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;  </span><span style="color:#e6db74">{</span>k<span style="color:#e6db74">}</span><span style="color:#e6db74">: </span><span style="color:#e6db74">{</span>v<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span></code></pre></div><p>Run it with <code>python3 containers.py CVE-2026-46300.json</code>, using a record file from the cvelistV5 repository (<code>cves/2026/46xxx/CVE-2026-46300.json</code>). It is a reading aid, not a merge engine; the next section is about merging.</p>
<h2 id="how-to-merge-adp-data-without-lying-to-yourself">How to merge ADP data without lying to yourself</h2>
<p>There is no Program-defined precedence between ADPs. The following policy is our editorial recommendation, built on the rules quoted above:</p>
<ol>
<li><strong>Always read <code>cna</code> and the <code>CVE</code> container.</strong> The README calls them the minimum. Union and deduplicate references across both.</li>
<li><strong>Store values with their provider.</strong> Keep <code>cvss_cna</code>, <code>cvss_cisa_adp</code> and <code>cvss_supplier</code> side by side rather than one <code>cvss</code> column. The same goes for CWE.</li>
<li><strong>Prefer the CNA for scoring, fall back to CISA-ADP.</strong> Use the CNA&rsquo;s CVSS when present; use CISA-ADP&rsquo;s when the CNA gave none (the common case in our sample); flag disagreements for a human when both exist.</li>
<li><strong>Take SSVC and the KEV date from CISA-ADP.</strong> No other container in our sample carried them. Then confirm KEV details against the catalog.</li>
<li><strong>Scope supplier data to the supplier.</strong> Use redhat-SADP <code>affected</code> entries only to match Red Hat packages, and siemens-SADP entries only for Siemens products. Never use them to clear or confirm an upstream version.</li>
<li><strong>Do not ignore unknown publishers.</strong> Log any new <code>shortName</code> so a person can decide how to treat it, rather than dropping it silently.</li>
<li><strong>Check the record state first.</strong> A rejected record has no ADP data to act on; see our guide to <a href="/posts/cve-record-states-published-rejected-and-disputed-what-each-means-for-vulnerability-triage/">CVE record states</a>.</li>
</ol>
<p>These steps fit into the record-reading stage of our <a href="/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/">vulnerability prioritization workflow</a>, which takes a CVE from record to patch ticket.</p>
<h2 id="common-mistakes">Common mistakes</h2>
<ul>
<li><strong>Reading only <code>containers.cna</code>.</strong> You lose CISA&rsquo;s SSVC and KEV signals, about one in five CVSS scores in our 2026 sample, and Program-added references.</li>
<li><strong>Taking <code>adp[0]</code>.</strong> Container order is not a precedence order. In CVE-2026-46300, CISA-ADP came last.</li>
<li><strong>Merging CWE lists without provenance.</strong> Red Hat and CISA mapped the same CVE to different CWEs. A merged list hides that they disagree.</li>
<li><strong>Matching upstream versions against supplier entries.</strong> RPM release strings and Siemens firmware versions are not kernel versions.</li>
<li><strong>Hard-coding today&rsquo;s publisher list.</strong> Supplier ADP is new. More publishers will appear.</li>
</ul>
<h2 id="limits-of-this-article">Limits of this article</h2>
<p>The sample covers 2,000 of 84,066 2026 record files in cvelistV5 on November 3, 2026, chosen at random, and 2026 records only. Shares will differ for older years, since the README says the CISA-ADP container was launched on June 4 (2024) and applied back to February 2024. We could not load cve.org&rsquo;s ADP pages (they render with JavaScript), so the description of supplier ADPs relies on Siemens&rsquo; own page and on the records themselves. <code>x_adpType</code> is an extension field, not part of the schema. We did not check how NVD or commercial scanners consume ADP data.</p>
<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>One cna container, multiple adp containers; ADP requires only providerMetadata; x_ extensions allowed</td>
          <td><a href="https://github.com/CVEProject/cve-schema/blob/main/schema/CVE_Record_Format.json">CVE JSON schema, CVE_Record_Format.json</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CVE Program Container: shortName CVE, Program references after 7/31/2024, CNA + Program container are the minimum</td>
          <td><a href="https://github.com/CVEProject/cvelistV5/blob/main/README.md">cvelistV5 README</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CISA-ADP provides SSVC, KEV data and Vulnrichment; launched June 4</td>
          <td><a href="https://github.com/CVEProject/cvelistV5/blob/main/README.md">cvelistV5 README</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CISA fills CVSS/CWE where the CNA has not and does not overwrite CNA data</td>
          <td><a href="https://github.com/cisagov/vulnrichment/blob/develop/README.md">CISA Vulnrichment README</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Supplier ADP purpose and April 2026 introduction</td>
          <td><a href="https://www.siemens.com/en-gb/content/cert-services-sadp/">Siemens: CERT services, SADP</a></td>
          <td>Qualified (vendor page)</td>
      </tr>
      <tr>
          <td>Sample shares (93.9%, 2.2%, 1.2%, 19.8%, 17.1%, 5 KEV blocks; 381/389, 326/336)</td>
          <td>Our count over 2,000 random files from <a href="https://github.com/CVEProject/cvelistV5">cvelistV5</a> at commit 1a44d59</td>
          <td>Verified (code)</td>
      </tr>
      <tr>
          <td>CVE-2026-46300 container contents</td>
          <td><a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/46xxx/CVE-2026-46300.json">cvelistV5 record</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CVE-2026-46300 KEV dateAdded 2026-10-28</td>
          <td><a href="https://github.com/cisagov/kev-data">CISA KEV data</a></td>
          <td>Verified</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>Vulnerability Prioritization Workflow: CVE Record to Ticket</title><link>https://firewallsync.com/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/</link><guid>https://firewallsync.com/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/</guid><pubDate>Mon, 02 Nov 2026 04:30:00 +0000</pubDate><dc:creator>John Marshall</dc:creator><category>Security Operations</category><description>A six-step patch-decision flow that takes a scanner finding from CVE record to ticket: check the record state, confirm you are affected, apply supplier VEX, read KEV and CISA's SSVC values, add EPSS, then let your exposure decide. Includes a tested Python script that writes the ticket fields.</description><enclosure url="https://firewallsync.com/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/cover_hu7197188011340061090.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/cover_hu7197188011340061090.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/cover_hu7197188011340061090.jpg" alt="View from the side of a passenger train of a railway switch where the tracks split, with a red point indicator, dry golden grassland and brown mountains behind" width="1200" height="630"></p><p><strong>Scope.</strong> This is a workflow guide built on public specifications and feeds, plus one script we ran. On November 2, 2026 we read the CVE JSON schema (5.2.0), CISA&rsquo;s Vulnrichment README, CERT/CC&rsquo;s SSVC deployer documentation and decision table, the OpenVEX specification and the EPSS repository README, and ran the script below against the KEV catalog (version 2026.10.30), the EPSS file scored 2026-11-01 and CVE records from cvelistV5. The assets, exposure ratings and the VEX document in the test are invented for the demonstration. The policy choices in the script are ours, not a standard.</p>
<h2 id="the-workflow-in-one-table">The workflow in one table</h2>
<p>Our comparison of <a href="/posts/cvss-vs-epss-vs-kev-which-signal-should-decide-what-you-patch-first/">CVSS, EPSS and KEV</a> explains what each signal measures. This guide is the plumbing: the order in which a finding from a scanner or SBOM passes through the data, and what lands in the ticket.</p>
<table>
  <thead>
      <tr>
          <th>Step</th>
          <th>Question</th>
          <th>Data you read</th>
          <th>Possible outcome</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>Is the CVE record valid?</td>
          <td><code>cveMetadata.state</code> in the CVE record</td>
          <td>Close if <code>REJECTED</code></td>
      </tr>
      <tr>
          <td>2</td>
          <td>Do we run an affected version?</td>
          <td><code>containers.cna.affected</code>: <code>versions</code>, <code>defaultStatus</code></td>
          <td>Close if unaffected; escalate if unknown</td>
      </tr>
      <tr>
          <td>3</td>
          <td>Has the supplier said we are not affected?</td>
          <td>VEX statement for this product</td>
          <td>Close with the VEX justification</td>
      </tr>
      <tr>
          <td>4</td>
          <td>Is it being exploited?</td>
          <td>KEV entry; CISA ADP SSVC <code>Exploitation</code></td>
          <td>Sets the Exploitation input</td>
      </tr>
      <tr>
          <td>5</td>
          <td>How likely is exploitation?</td>
          <td>EPSS <code>epss</code>, <code>percentile</code></td>
          <td>Re-orders the non-exploited queue</td>
      </tr>
      <tr>
          <td>6</td>
          <td>How exposed and important is this asset?</td>
          <td>Your inventory: System Exposure, Human Impact</td>
          <td>Priority: Defer, Scheduled, Out-of-cycle, Immediate</td>
      </tr>
  </tbody>
</table>
<p>Steps 1 to 3 remove work. Steps 4 to 6 order what remains.</p>
<h2 id="step-1-check-the-record-state">Step 1: check the record state</h2>
<p>A CVE record is either <code>PUBLISHED</code> or <code>REJECTED</code> (the schema&rsquo;s two states), and published records can carry tags such as <code>disputed</code>. A rejected ID has no affected products to evaluate. In our test run, CVE-2026-23915 is a Fortinet-assigned ID that was rejected on January 20, 2026 with the reason &ldquo;Not used&rdquo;, so the finding closes. Our guide to <a href="/posts/cve-record-states-published-rejected-and-disputed-what-each-means-for-vulnerability-triage/">CVE record states</a> covers the tags and edge cases.</p>
<h2 id="step-2-confirm-you-are-affected">Step 2: confirm you are affected</h2>
<p>The CNA&rsquo;s <code>affected</code> block is an algorithm, not a list: walk <code>versions</code>, take the first match, otherwise use <code>defaultStatus</code>, and if that is missing the schema says the status is <code>unknown</code>. Scanner results that only match a product name skip this. Our explainer on <a href="/posts/cve-affected-versions-lessthan-defaultstatus-versiontype/">CVE affected versions</a> shows how <code>lessThan</code>, <code>defaultStatus</code> and <code>versionType</code> combine, with a tested evaluator. Keep three outcomes apart in the ticket: affected, unaffected, and unknown or undetermined. The last needs a person or the vendor advisory.</p>
<h2 id="step-3-apply-supplier-vex">Step 3: apply supplier VEX</h2>
<p>If the vulnerable component ships inside someone else&rsquo;s product, the supplier may publish a VEX (Vulnerability Exploitability eXchange) statement. OpenVEX defines four statuses: <code>not_affected</code> (&ldquo;No remediation is required regarding this vulnerability&rdquo;), <code>affected</code>, <code>fixed</code> and <code>under_investigation</code>. A <code>not_affected</code> statement must carry a justification or an impact statement.</p>
<p>Two cautions. A VEX statement is about a specific product and version, so match on the product identifier, not on the CVE alone; a <code>not_affected</code> statement from an appliance vendor says nothing about your own services that use the same library. And read the justification before closing. Our guide to <a href="/posts/vex-explained-what-a-not-affected-statement-means-and-how-to-read-one/">reading a VEX not-affected statement</a> covers the five justifications and what to question.</p>
<h2 id="step-4-read-the-exploitation-evidence">Step 4: read the exploitation evidence</h2>
<p>Two public sources answer &ldquo;is this being exploited?&rdquo;:</p>
<ul>
<li><strong>KEV.</strong> The <a href="/posts/cisa-kev-json-feed-what-each-field-means-and-how-to-match-it-against-a-scanner-export/">CISA KEV JSON feed</a> lists CVEs with evidence of exploitation, with <code>dateAdded</code>, <code>dueDate</code>, <code>knownRansomwareCampaignUse</code> and, on newer entries, <code>forensicTriage</code>. The catalog we used (version 2026.10.30, released October 30, 2026) had 1,766 entries.</li>
<li><strong>CISA&rsquo;s SSVC values in the CVE record.</strong> CISA&rsquo;s Vulnrichment project writes three SSVC decision points (Exploitation, Automatable, Technical Impact) into a CISA-ADP container. Its README says CISA is &ldquo;assessing new and recent CVEs&rdquo;, and that it will not overwrite the CNA&rsquo;s data. Each value set carries a timestamp. Our <a href="/posts/cisa-vulnrichment-how-to-read-ssvc-values-in-a-cve-record-and-turn-them-into-a-patch-decision/">Vulnrichment guide</a> shows where they sit and how to pull them with jq.</li>
</ul>
<p>The SSVC documentation describes Exploitation as &ldquo;the present state of exploitation&rdquo;, not a prediction. A <code>none</code> from months ago can be stale, so a KEV listing should outrank an older ADP value. That is the rule our script applies.</p>
<h2 id="step-5-add-epss-for-likelihood">Step 5: add EPSS for likelihood</h2>
<p>For findings with no exploitation evidence, EPSS estimates &ldquo;the probability [0-1] of exploitation in the wild in the next 30 days&rdquo;, and <code>percentile</code> gives the share of scored CVEs with the same or a lower score. The file we used (model v2026.06.15, scored 2026-11-01) held 398,784 CVEs. EPSS is a ranking aid within the non-exploited queue. It does not replace step 4: in our run the KEV-listed FortiMail flaw scored 0.04573. See the <a href="/posts/epss-data-feed-columns-percentile-vs-probability-and-how-to-join-it-to-a-scanner-export/">EPSS data feed guide</a> for the columns, model-version breaks and a scanner join.</p>
<h2 id="step-6-let-exposure-and-impact-decide">Step 6: let exposure and impact decide</h2>
<p>CERT/CC&rsquo;s SSVC deployer model maps four inputs to a patch priority:</p>
<table>
  <thead>
      <tr>
          <th>Input</th>
          <th>Values</th>
          <th>Who supplies it</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Exploitation</td>
          <td>none, public poc, active</td>
          <td>CISA ADP or KEV, or your own research</td>
      </tr>
      <tr>
          <td>System Exposure</td>
          <td>small, controlled, open</td>
          <td>You, per asset</td>
      </tr>
      <tr>
          <td>Automatable</td>
          <td>no, yes</td>
          <td>CISA ADP, or your own analysis</td>
      </tr>
      <tr>
          <td>Human Impact</td>
          <td>low, medium, high, very high</td>
          <td>You, per asset</td>
      </tr>
  </tbody>
</table>
<p>The decision table (<code>deployer_patch_application_priority_1_0_0.csv</code>, 72 rows) returns one of four outcomes, which the deployer documentation defines as: Defer (&ldquo;Do not act at present&rdquo;), Scheduled (&ldquo;Act during regularly scheduled maintenance time&rdquo;), Out-of-cycle (&ldquo;Act more quickly than usual&hellip; during the next available opportunity&rdquo;) and Immediate (&ldquo;Act immediately; focus all resources on applying the fix&rdquo;). In the table, Immediate appears in 3 rows, all with active exploitation and open exposure. Our <a href="/posts/ssvc-deployer-patch-priority-model-explained-exploitation-exposure-automatable-and-human-impact/">SSVC deployer explainer</a> walks through the inputs, including where Human Impact is easy to get wrong.</p>
<p>One mapping detail: CISA&rsquo;s ADP data writes <code>poc</code>, while the deployer table uses <code>public poc</code>. They are not identical definitions. CISA&rsquo;s tree uses the older PoC value, which also covers privately attested exploitation and widespread hearsay; the newer Public PoC value covers only public exploit code or a well-known method. Our script maps one to the other, which can understate cases CISA marked <code>poc</code> on private evidence.</p>
<h2 id="a-tested-script-that-writes-the-ticket-fields">A tested script that writes the ticket fields</h2>
<p>The script reads a findings CSV, the KEV JSON, the EPSS daily file, the SSVC deployer CSV, a folder of CVE records and an optional OpenVEX file, and prints one ticket row per finding. Python 3.10 or later, standard library only.</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:#75715e">#!/usr/bin/env python3</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;Turn scanner findings into patch-decision ticket rows.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Inputs : findings.csv (asset,product,cve,exposure,human_impact)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">         KEV JSON, EPSS daily CSV (.csv.gz), SSVC deployer table CSV,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">         a directory of cvelistV5 records, optional OpenVEX file.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Output : tickets.csv on stdout. Python 3.10+, standard library only.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> csv<span style="color:#f92672">,</span> gzip<span style="color:#f92672">,</span> json<span style="color:#f92672">,</span> sys<span style="color:#f92672">,</span> argparse<span style="color:#f92672">,</span> pathlib
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">load_kev</span>(path):
</span></span><span style="display:flex;"><span>    data <span style="color:#f92672">=</span> json<span style="color:#f92672">.</span>load(open(path))
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> {v[<span style="color:#e6db74">&#34;cveID&#34;</span>]<span style="color:#f92672">.</span>strip()<span style="color:#f92672">.</span>upper(): v <span style="color:#66d9ef">for</span> v <span style="color:#f92672">in</span> data[<span style="color:#e6db74">&#34;vulnerabilities&#34;</span>]}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">load_epss</span>(path):
</span></span><span style="display:flex;"><span>    scores <span style="color:#f92672">=</span> {}
</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> fh:
</span></span><span style="display:flex;"><span>        rows <span style="color:#f92672">=</span> (line <span style="color:#66d9ef">for</span> line <span style="color:#f92672">in</span> fh <span style="color:#66d9ef">if</span> <span style="color:#f92672">not</span> line<span style="color:#f92672">.</span>startswith(<span style="color:#e6db74">&#34;#&#34;</span>))
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> r <span style="color:#f92672">in</span> csv<span style="color:#f92672">.</span>DictReader(rows):
</span></span><span style="display:flex;"><span>            scores[r[<span style="color:#e6db74">&#34;cve&#34;</span>]] <span style="color:#f92672">=</span> (float(r[<span style="color:#e6db74">&#34;epss&#34;</span>]), float(r[<span style="color:#e6db74">&#34;percentile&#34;</span>]))
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> scores
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">load_deployer</span>(path):
</span></span><span style="display:flex;"><span>    rows <span style="color:#f92672">=</span> list(csv<span style="color:#f92672">.</span>reader(open(path)))
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> {tuple(r[<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">5</span>]): r[<span style="color:#ae81ff">5</span>] <span style="color:#66d9ef">for</span> r <span style="color:#f92672">in</span> rows[<span style="color:#ae81ff">1</span>:]}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">load_vex</span>(path):
</span></span><span style="display:flex;"><span>    out <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> path:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> s <span style="color:#f92672">in</span> json<span style="color:#f92672">.</span>load(open(path))<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;statements&#34;</span>, []):
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">for</span> p <span style="color:#f92672">in</span> s<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;products&#34;</span>, []):
</span></span><span style="display:flex;"><span>                out[(s[<span style="color:#e6db74">&#34;vulnerability&#34;</span>][<span style="color:#e6db74">&#34;name&#34;</span>]<span style="color:#f92672">.</span>upper(), p[<span style="color:#e6db74">&#34;@id&#34;</span>])] <span style="color:#f92672">=</span> s
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> out
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">cisa_ssvc</span>(record):
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;&#34;&#34;Return CISA ADP SSVC values (Exploitation, Automatable, Technical Impact, timestamp).&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> adp <span style="color:#f92672">in</span> record[<span style="color:#e6db74">&#34;containers&#34;</span>]<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;adp&#34;</span>, []):
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> m <span style="color:#f92672">in</span> adp<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;metrics&#34;</span>, []):
</span></span><span style="display:flex;"><span>            other <span style="color:#f92672">=</span> m<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;other&#34;</span>, {})
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">if</span> other<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;type&#34;</span>) <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;ssvc&#34;</span>:
</span></span><span style="display:flex;"><span>                c <span style="color:#f92672">=</span> other[<span style="color:#e6db74">&#34;content&#34;</span>]
</span></span><span style="display:flex;"><span>                opts <span style="color:#f92672">=</span> {k: v <span style="color:#66d9ef">for</span> o <span style="color:#f92672">in</span> c[<span style="color:#e6db74">&#34;options&#34;</span>] <span style="color:#66d9ef">for</span> k, v <span style="color:#f92672">in</span> o<span style="color:#f92672">.</span>items()}
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">return</span> (opts<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;Exploitation&#34;</span>), opts<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;Automatable&#34;</span>),
</span></span><span style="display:flex;"><span>                        opts<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;Technical Impact&#34;</span>), c<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;timestamp&#34;</span>))
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> (<span style="color:#66d9ef">None</span>, <span style="color:#66d9ef">None</span>, <span style="color:#66d9ef">None</span>, <span style="color:#66d9ef">None</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">main</span>():
</span></span><span style="display:flex;"><span>    ap <span style="color:#f92672">=</span> argparse<span style="color:#f92672">.</span>ArgumentParser()
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> a <span style="color:#f92672">in</span> (<span style="color:#e6db74">&#34;findings&#34;</span>, <span style="color:#e6db74">&#34;kev&#34;</span>, <span style="color:#e6db74">&#34;epss&#34;</span>, <span style="color:#e6db74">&#34;deployer&#34;</span>, <span style="color:#e6db74">&#34;records&#34;</span>):
</span></span><span style="display:flex;"><span>        ap<span style="color:#f92672">.</span>add_argument(a)
</span></span><span style="display:flex;"><span>    ap<span style="color:#f92672">.</span>add_argument(<span style="color:#e6db74">&#34;--vex&#34;</span>)
</span></span><span style="display:flex;"><span>    args <span style="color:#f92672">=</span> ap<span style="color:#f92672">.</span>parse_args()
</span></span><span style="display:flex;"><span>    kev, epss <span style="color:#f92672">=</span> load_kev(args<span style="color:#f92672">.</span>kev), load_epss(args<span style="color:#f92672">.</span>epss)
</span></span><span style="display:flex;"><span>    table, vex <span style="color:#f92672">=</span> load_deployer(args<span style="color:#f92672">.</span>deployer), load_vex(args<span style="color:#f92672">.</span>vex)
</span></span><span style="display:flex;"><span>    out <span style="color:#f92672">=</span> csv<span style="color:#f92672">.</span>writer(sys<span style="color:#f92672">.</span>stdout)
</span></span><span style="display:flex;"><span>    out<span style="color:#f92672">.</span>writerow([<span style="color:#e6db74">&#34;asset&#34;</span>, <span style="color:#e6db74">&#34;cve&#34;</span>, <span style="color:#e6db74">&#34;record_state&#34;</span>, <span style="color:#e6db74">&#34;vex_status&#34;</span>, <span style="color:#e6db74">&#34;kev_dateAdded&#34;</span>,
</span></span><span style="display:flex;"><span>                  <span style="color:#e6db74">&#34;kev_dueDate&#34;</span>, <span style="color:#e6db74">&#34;kev_ransomware&#34;</span>, <span style="color:#e6db74">&#34;cisa_exploitation&#34;</span>, <span style="color:#e6db74">&#34;cisa_automatable&#34;</span>,
</span></span><span style="display:flex;"><span>                  <span style="color:#e6db74">&#34;cisa_technical_impact&#34;</span>, <span style="color:#e6db74">&#34;cisa_ssvc_timestamp&#34;</span>, <span style="color:#e6db74">&#34;epss&#34;</span>, <span style="color:#e6db74">&#34;epss_percentile&#34;</span>,
</span></span><span style="display:flex;"><span>                  <span style="color:#e6db74">&#34;deployer_exploitation&#34;</span>, <span style="color:#e6db74">&#34;deployer_priority&#34;</span>, <span style="color:#e6db74">&#34;next_step&#34;</span>])
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> f <span style="color:#f92672">in</span> csv<span style="color:#f92672">.</span>DictReader(open(args<span style="color:#f92672">.</span>findings)):
</span></span><span style="display:flex;"><span>        cve <span style="color:#f92672">=</span> f[<span style="color:#e6db74">&#34;cve&#34;</span>]<span style="color:#f92672">.</span>strip()<span style="color:#f92672">.</span>upper()
</span></span><span style="display:flex;"><span>        rec_path <span style="color:#f92672">=</span> pathlib<span style="color:#f92672">.</span>Path(args<span style="color:#f92672">.</span>records) <span style="color:#f92672">/</span> <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>cve<span style="color:#e6db74">}</span><span style="color:#e6db74">.json&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">not</span> rec_path<span style="color:#f92672">.</span>exists():
</span></span><span style="display:flex;"><span>            out<span style="color:#f92672">.</span>writerow([f[<span style="color:#e6db74">&#34;asset&#34;</span>], cve, <span style="color:#e6db74">&#34;NO RECORD&#34;</span>] <span style="color:#f92672">+</span> [<span style="color:#e6db74">&#34;&#34;</span>] <span style="color:#f92672">*</span> <span style="color:#ae81ff">12</span> <span style="color:#f92672">+</span> [<span style="color:#e6db74">&#34;check the ID&#34;</span>])
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">continue</span>
</span></span><span style="display:flex;"><span>        rec <span style="color:#f92672">=</span> json<span style="color:#f92672">.</span>load(open(rec_path))
</span></span><span style="display:flex;"><span>        state <span style="color:#f92672">=</span> rec[<span style="color:#e6db74">&#34;cveMetadata&#34;</span>][<span style="color:#e6db74">&#34;state&#34;</span>]
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> state <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;REJECTED&#34;</span>:
</span></span><span style="display:flex;"><span>            out<span style="color:#f92672">.</span>writerow([f[<span style="color:#e6db74">&#34;asset&#34;</span>], cve, state] <span style="color:#f92672">+</span> [<span style="color:#e6db74">&#34;&#34;</span>] <span style="color:#f92672">*</span> <span style="color:#ae81ff">12</span> <span style="color:#f92672">+</span> [<span style="color:#e6db74">&#34;close: CVE ID rejected&#34;</span>])
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">continue</span>
</span></span><span style="display:flex;"><span>        v <span style="color:#f92672">=</span> vex<span style="color:#f92672">.</span>get((cve, f<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;product&#34;</span>, <span style="color:#e6db74">&#34;&#34;</span>)), {})  <span style="color:#75715e"># VEX applies to one product, not every asset</span>
</span></span><span style="display:flex;"><span>        k <span style="color:#f92672">=</span> kev<span style="color:#f92672">.</span>get(cve, {})
</span></span><span style="display:flex;"><span>        exp, auto, ti, ts <span style="color:#f92672">=</span> cisa_ssvc(rec)
</span></span><span style="display:flex;"><span>        e, pct <span style="color:#f92672">=</span> epss<span style="color:#f92672">.</span>get(cve, (<span style="color:#e6db74">&#34;&#34;</span>, <span style="color:#e6db74">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># Our policy choice: a KEV listing counts as active exploitation, whatever</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># the (possibly older) CISA ADP snapshot says. CISA writes &#34;poc&#34;; the</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># deployer table writes &#34;public poc&#34;.</span>
</span></span><span style="display:flex;"><span>        dexp <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;active&#34;</span> <span style="color:#66d9ef">if</span> k <span style="color:#66d9ef">else</span> {<span style="color:#e6db74">&#34;poc&#34;</span>: <span style="color:#e6db74">&#34;public poc&#34;</span>}<span style="color:#f92672">.</span>get(exp, exp)
</span></span><span style="display:flex;"><span>        prio <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> dexp <span style="color:#f92672">and</span> auto:
</span></span><span style="display:flex;"><span>            prio <span style="color:#f92672">=</span> table<span style="color:#f92672">.</span>get((dexp, f[<span style="color:#e6db74">&#34;exposure&#34;</span>], auto, f[<span style="color:#e6db74">&#34;human_impact&#34;</span>]), <span style="color:#e6db74">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> v<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;status&#34;</span>) <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;not_affected&#34;</span>:
</span></span><span style="display:flex;"><span>            step <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;close: supplier VEX not_affected (&#34;</span> <span style="color:#f92672">+</span> v<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;justification&#34;</span>, <span style="color:#e6db74">&#34;no justification&#34;</span>) <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;)&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">elif</span> <span style="color:#f92672">not</span> prio:
</span></span><span style="display:flex;"><span>            step <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;manual triage: no CISA SSVC data&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">else</span>:
</span></span><span style="display:flex;"><span>            step <span style="color:#f92672">=</span> prio
</span></span><span style="display:flex;"><span>        out<span style="color:#f92672">.</span>writerow([f[<span style="color:#e6db74">&#34;asset&#34;</span>], cve, state, v<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;status&#34;</span>, <span style="color:#e6db74">&#34;&#34;</span>), k<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;dateAdded&#34;</span>, <span style="color:#e6db74">&#34;&#34;</span>),
</span></span><span style="display:flex;"><span>                      k<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;dueDate&#34;</span>, <span style="color:#e6db74">&#34;&#34;</span>), k<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;knownRansomwareCampaignUse&#34;</span>, <span style="color:#e6db74">&#34;&#34;</span>),
</span></span><span style="display:flex;"><span>                      exp <span style="color:#f92672">or</span> <span style="color:#e6db74">&#34;&#34;</span>, auto <span style="color:#f92672">or</span> <span style="color:#e6db74">&#34;&#34;</span>, ti <span style="color:#f92672">or</span> <span style="color:#e6db74">&#34;&#34;</span>, ts <span style="color:#f92672">or</span> <span style="color:#e6db74">&#34;&#34;</span>, e, pct, dexp <span style="color:#f92672">or</span> <span style="color:#e6db74">&#34;&#34;</span>, prio, step])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> __name__ <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    main()
</span></span></code></pre></div><p>The test input (<code>findings.csv</code>) used invented assets with real CVE IDs:</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>asset,product,cve,exposure,human_impact
</span></span><span style="display:flex;"><span>edge-mail-01,fortimail,CVE-2026-104286,open,high
</span></span><span style="display:flex;"><span>k8s-node-17,linux-kernel,CVE-2026-46300,controlled,medium
</span></span><span style="display:flex;"><span>build-runner-03,pkg:cargo/gix-fs@0.22.1,CVE-2026-100419,small,medium
</span></span><span style="display:flex;"><span>billing-api,pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1,CVE-2021-44228,open,very high
</span></span><span style="display:flex;"><span>vendor-appliance-2,pkg:generic/example-appliance@4.2,CVE-2021-44228,open,very high
</span></span><span style="display:flex;"><span>legacy-scan,unknown,CVE-2026-23915,open,low
</span></span></code></pre></div><p>The VEX file is an invented OpenVEX document from an &ldquo;Example Appliance Vendor&rdquo; stating <code>not_affected</code> with justification <code>vulnerable_code_not_present</code> for CVE-2021-44228 in <code>pkg:generic/example-appliance@4.2</code>. We ran:</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-bash" data-lang="bash"><span style="display:flex;"><span>python3 patch_decision.py findings.csv known_exploited_vulnerabilities.json <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  epss_scores-2026-11-01.csv.gz deployer_patch_application_priority_1_0_0.csv <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  records/ --vex vendor.openvex.json &gt; tickets.csv
</span></span></code></pre></div><p>The data came from <code>raw.githubusercontent.com/cisagov/kev-data</code>, the <code>empiricalsec/epss_scores</code> repository (2026/epss_scores-2026-11-01.csv.gz), <code>CERTCC/SSVC</code> (data/csv/ssvc/) and <code>CVEProject/cvelistV5</code> at commit 451e97a. Output, with some columns dropped for width:</p>
<table>
  <thead>
      <tr>
          <th>Asset</th>
          <th>CVE</th>
          <th>KEV added</th>
          <th>CISA SSVC (E / A / TI)</th>
          <th>EPSS (percentile)</th>
          <th>Deployer priority</th>
          <th>Next step</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>edge-mail-01</td>
          <td>CVE-2026-104286</td>
          <td>2026-10-01</td>
          <td>active / yes / total</td>
          <td>0.04573 (0.916)</td>
          <td>immediate</td>
          <td>immediate</td>
      </tr>
      <tr>
          <td>k8s-node-17</td>
          <td>CVE-2026-46300</td>
          <td>2026-10-28</td>
          <td>active / no / total</td>
          <td>0.1613 (0.969)</td>
          <td>scheduled</td>
          <td>scheduled</td>
      </tr>
      <tr>
          <td>build-runner-03</td>
          <td>CVE-2026-100419</td>
          <td>-</td>
          <td>poc / no / total</td>
          <td>0.00222 (0.129)</td>
          <td>scheduled</td>
          <td>scheduled</td>
      </tr>
      <tr>
          <td>billing-api</td>
          <td>CVE-2021-44228</td>
          <td>2021-12-10</td>
          <td>active / yes / total</td>
          <td>0.99999 (1.0)</td>
          <td>immediate</td>
          <td>immediate</td>
      </tr>
      <tr>
          <td>vendor-appliance-2</td>
          <td>CVE-2021-44228</td>
          <td>2021-12-10</td>
          <td>active / yes / total</td>
          <td>0.99999 (1.0)</td>
          <td>immediate</td>
          <td>close: supplier VEX not_affected (vulnerable_code_not_present)</td>
      </tr>
      <tr>
          <td>legacy-scan</td>
          <td>CVE-2026-23915</td>
          <td>-</td>
          <td>-</td>
          <td>-</td>
          <td>-</td>
          <td>close: CVE ID rejected</td>
      </tr>
  </tbody>
</table>
<p>Three things in that output are worth noticing:</p>
<ul>
<li><strong>The same CVE got two different answers</strong> (Log4Shell rows) because the VEX statement applies to one product only.</li>
<li><strong>A KEV-listed kernel flaw came out Scheduled.</strong> CVE-2026-46300 is in KEV with <code>forensicTriage: Yes</code> and a three-day federal due date, but with controlled exposure, no automatability and medium Human Impact the deployer table says Scheduled. If you follow CISA&rsquo;s directives, the due date wins. If you do not, the table is telling you the exposure is what drives urgency. Either way, keep both fields in the ticket, and consider a compromise check when <code>forensicTriage</code> is Yes; our <a href="/posts/cisa-bod-26-04-explained-kev-deadlines-forensic-triage-and-what-private-teams-can-borrow/">BOD 26-04 explainer</a> covers what that flag asks agencies to do.</li>
<li><strong>EPSS and KEV disagreed</strong> on FortiMail, as expected: one estimates future observed activity, the other records evidence already seen.</li>
</ul>
<h2 id="what-the-ticket-should-hold">What the ticket should hold</h2>
<p>Store the inputs, not just the priority, so a reviewer can see why. A suggested field list (ours, not a standard):</p>
<table>
  <thead>
      <tr>
          <th>Field</th>
          <th>Why</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Asset, product identifier (purl or CPE), version</td>
          <td>Ties VEX and affected checks to the right thing</td>
      </tr>
      <tr>
          <td>CVE ID, record state, record <code>dateUpdated</code></td>
          <td>Detects rejected IDs and record changes</td>
      </tr>
      <tr>
          <td>Affected status and how it was decided</td>
          <td>&ldquo;unknown&rdquo; needs a different owner from &ldquo;affected&rdquo;</td>
      </tr>
      <tr>
          <td>VEX status, justification, document author and timestamp</td>
          <td>Audit trail for closures</td>
      </tr>
      <tr>
          <td>KEV <code>dateAdded</code>, <code>dueDate</code>, <code>knownRansomwareCampaignUse</code>, <code>forensicTriage</code></td>
          <td>Exploitation evidence and any federal deadline</td>
      </tr>
      <tr>
          <td>CISA SSVC Exploitation, Automatable, Technical Impact, timestamp</td>
          <td>Shows how fresh the assessment is</td>
      </tr>
      <tr>
          <td>EPSS score, percentile, model version, score date</td>
          <td>Scores shift when the model changes</td>
      </tr>
      <tr>
          <td>Your System Exposure and Human Impact</td>
          <td>The inputs only you can supply</td>
      </tr>
      <tr>
          <td>Priority and data pull date</td>
          <td>Lets you re-run and compare</td>
      </tr>
  </tbody>
</table>
<h2 id="keeping-it-current">Keeping it current</h2>
<p>The feeds move at different speeds: CISA updates KEV on weekdays, EPSS publishes daily, and CVE records and VEX documents change when their authors revise them. Re-run the flow on a schedule and on any change to a ticket&rsquo;s inputs, and alert when a finding&rsquo;s priority rises. Set your service-level targets per priority (for example, how many days &ldquo;Out-of-cycle&rdquo; means for you) in policy, not in the script; the deployer model does not define days.</p>
<h2 id="limits-of-this-article">Limits of this article</h2>
<p>The script is a working example, not a product. It reads CVE records from a local folder (it does not fetch them), does not evaluate affected versions itself (pair it with a version check such as the evaluator in our affected-versions guide), handles OpenVEX JSON only, and uses one policy choice (KEV overrides an older CISA Exploitation value) that you may want to change. The four-value deployer inputs simplify real decisions: SSVC expects organizations to adapt trees to their context. We did not test it against commercial scanner exports.</p>
<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>CVE record states, <code>affected</code> algorithm, <code>defaultStatus</code> defaults to unknown</td>
          <td><a href="https://github.com/CVEProject/cve-schema/blob/main/schema/CVE_Record_Format.json">CVE JSON schema (CVE_Record_Format.json, 5.2.0)</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CVE-2026-23915 rejected, reason &ldquo;Not used&rdquo;; SSVC values and timestamps for the test CVEs</td>
          <td><a href="https://github.com/CVEProject/cvelistV5">cvelistV5</a>, commit 451e97a</td>
          <td>Verified (read November 2, 2026)</td>
      </tr>
      <tr>
          <td>Vulnrichment assesses &ldquo;new and recent CVEs&rdquo;, adds SSVC decision points, never overwrites CNA data</td>
          <td><a href="https://github.com/cisagov/vulnrichment">cisagov/vulnrichment README</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>KEV catalog 2026.10.30, 1,766 entries; dates and flags for the test CVEs</td>
          <td><a href="https://github.com/cisagov/kev-data">cisagov/kev-data</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>EPSS field definitions; file model v2026.06.15, 398,784 CVEs; scores for the test CVEs</td>
          <td><a href="https://github.com/empiricalsec/epss_scores">empiricalsec/epss_scores</a></td>
          <td>Verified (computed from the file)</td>
      </tr>
      <tr>
          <td>Deployer inputs, values, 72-row table, outcome definitions, active never Defer</td>
          <td><a href="https://github.com/CERTCC/SSVC/blob/main/docs/howto/deployer_tree.md">CERT/CC SSVC deployer tree</a> and <a href="https://github.com/CERTCC/SSVC/blob/main/data/csv/ssvc/deployer_patch_application_priority_1_0_0.csv">decision table CSV</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Exploitation is &ldquo;the present state of exploitation&rdquo;; PoC vs Public PoC definitions</td>
          <td><a href="https://github.com/CERTCC/SSVC/blob/main/docs/reference/decision_points/exploitation.md">SSVC Exploitation decision point</a> and its source definitions</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>OpenVEX statuses and the justification requirement</td>
          <td><a href="https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md">OpenVEX specification</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Script output</td>
          <td>Script above, Python 3.13, run November 2, 2026</td>
          <td>Verified</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item></channel></rss>