<?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>Kev | FirewallSync</title><link>https://firewallsync.com/tags/kev/</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>Wed, 04 Nov 2026 04:40:00 +0000</lastBuildDate><atom:link href="https://firewallsync.com/tags/kev/index.xml" rel="self" type="application/rss+xml"/><item><title>WordPress CVE-2026-119977: Patch the Upgrade Race RCE</title><link>https://firewallsync.com/posts/wordpress-cve-2026-119977-upgrade-race-rce-kev/</link><guid>https://firewallsync.com/posts/wordpress-cve-2026-119977-upgrade-race-rce-kev/</guid><pubDate>Wed, 04 Nov 2026 04:40:00 +0000</pubDate><dc:creator>John Marshall</dc:creator><category>Security Operations</category><description>CISA added CVE-2026-119977 to the KEV catalog on 3 November 2026. In WordPress 4.7 through 7.1.3, a full-package core update stages a copy of WordPress, installer included, in a web-served folder under wp-content/upgrade, and an unauthenticated attacker who reaches it during the update window can run code. Here are the fixed versions per branch, what the 7.1.4 code change does, why the update itself is a risky moment, and what to check afterwards.</description><enclosure url="https://firewallsync.com/posts/wordpress-cve-2026-119977-upgrade-race-rce-kev/cover_hu7098877180882857123.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/wordpress-cve-2026-119977-upgrade-race-rce-kev/cover_hu7098877180882857123.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/wordpress-cve-2026-119977-upgrade-race-rce-kev/cover_hu7098877180882857123.jpg" alt="Looking up at steel scaffolding tubes, clamps and wooden boards fixed to the side of a brick building under construction" width="1200" height="630"></p><p><strong>Scope.</strong> This post is based on the CVE record published by Wordfence (the CNA), the CISA KEV entry and CISA&rsquo;s SSVC assessment, the WordPress 7.1.4 release notes, and a diff we ran of the WordPress 7.1.3 and 7.1.4 source files. The exploitation telemetry is Wordfence&rsquo;s, as reported by The Hacker News. We did not reproduce the attack.</p>
<h2 id="what-the-vulnerability-is">What the vulnerability is</h2>
<p>The CVE record&rsquo;s description says: &ldquo;WordPress Core is vulnerable to Remote Code Execution in versions 4.7 through 7.1.3. This is due to predictable, web-accessible staging paths used during full-package core upgrades. This makes it possible for unauthenticated attackers to execute code on the server during the upgrade window.&rdquo;</p>
<table>
  <thead>
      <tr>
          <th>Field</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CVE</td>
          <td>CVE-2026-119977</td>
      </tr>
      <tr>
          <td>CNA</td>
          <td>Wordfence (published 31 October 2026)</td>
      </tr>
      <tr>
          <td>Weakness</td>
          <td>CWE-367, Time-of-check Time-of-use (TOCTOU) race condition</td>
      </tr>
      <tr>
          <td>CVSS 3.1</td>
          <td>8.1 High, <code>AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H</code></td>
      </tr>
      <tr>
          <td>Reporter</td>
          <td>Umut Bayram</td>
      </tr>
      <tr>
          <td>KEV</td>
          <td>Added 3 November 2026; due 6 November 2026; ransomware use Unknown; forensic triage: Yes</td>
      </tr>
      <tr>
          <td>CISA SSVC</td>
          <td>Exploitation active, Automatable no, Technical Impact total</td>
      </tr>
  </tbody>
</table>
<p>The attack complexity is High for a reason: the attacker has to hit files that exist only while a core update runs. According to The Hacker News&rsquo;s summary of Wordfence&rsquo;s analysis, exploitation needs a full-package update that includes the installer files, public web and PHP access to the staging tree, a predictable or discovered staging path, and enough time before WordPress deletes the temporary files. The same report says attackers have been repeatedly polling paths such as <code>setup-config.php</code>.</p>
<p>&ldquo;Automatable: no&rdquo; in the SSVC entry does not make this low priority. It reflects the narrow timing window, not the impact. Combined with active exploitation and total technical impact, it still puts the CVE near the top of a queue; <a href="/posts/cisa-vulnrichment-how-to-read-ssvc-values-in-a-cve-record-and-turn-them-into-a-patch-decision/">our SSVC guide</a> shows how your own mission and exposure values turn those three into a decision, and every public WordPress site is internet-facing.</p>
<h2 id="fixed-versions">Fixed versions</h2>
<p>WordPress released 7.1.4 on 28 October 2026 and says: &ldquo;Because this is a security release, it is recommended that you update your sites immediately.&rdquo; The release fixes this issue (&ldquo;A race condition during core updates that could lead to remote code execution reported by Umut Bayram&rdquo;) along with 21 other listed items.</p>
<p>The CVE record lists 25 affected branches, each with an inclusive upper limit (<code>lessThanOrEqual</code>). We checked each against the backport list in the release notes; in every branch the fixed release is the next point release.</p>
<table>
  <thead>
      <tr>
          <th>Branch</th>
          <th>Last affected</th>
          <th>Fixed</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>7.1</td>
          <td>7.1.3</td>
          <td><strong>7.1.4</strong></td>
      </tr>
      <tr>
          <td>7.0</td>
          <td>7.0.7</td>
          <td>7.0.8</td>
      </tr>
      <tr>
          <td>6.9</td>
          <td>6.9.10</td>
          <td>6.9.11</td>
      </tr>
      <tr>
          <td>6.8</td>
          <td>6.8.11</td>
          <td>6.8.12</td>
      </tr>
      <tr>
          <td>6.7</td>
          <td>6.7.10</td>
          <td>6.7.11</td>
      </tr>
      <tr>
          <td>6.6</td>
          <td>6.6.10</td>
          <td>6.6.11</td>
      </tr>
      <tr>
          <td>6.5</td>
          <td>6.5.13</td>
          <td>6.5.14</td>
      </tr>
      <tr>
          <td>6.4</td>
          <td>6.4.13</td>
          <td>6.4.14</td>
      </tr>
      <tr>
          <td>6.3</td>
          <td>6.3.13</td>
          <td>6.3.14</td>
      </tr>
      <tr>
          <td>6.2</td>
          <td>6.2.14</td>
          <td>6.2.15</td>
      </tr>
      <tr>
          <td>6.1</td>
          <td>6.1.15</td>
          <td>6.1.16</td>
      </tr>
      <tr>
          <td>6.0</td>
          <td>6.0.17</td>
          <td>6.0.18</td>
      </tr>
      <tr>
          <td>5.0 to 5.9</td>
          <td>5.0.30 &hellip; 5.9.19</td>
          <td>5.0.31, 5.1.28, 5.2.30, 5.3.27, 5.4.25, 5.5.24, 5.6.23, 5.7.21, 5.8.19, 5.9.20</td>
      </tr>
      <tr>
          <td>4.7 to 4.9</td>
          <td>4.7.38, 4.8.33, 4.9.34</td>
          <td>4.7.39, 4.8.34, 4.9.35</td>
      </tr>
  </tbody>
</table>
<p>WordPress adds that backports are &ldquo;a courtesy&rdquo; and that &ldquo;only the most recent version of WordPress is actively supported.&rdquo; Sites on 4.6 or earlier get no fix at all.</p>
<h2 id="what-changed-in-714">What changed in 7.1.4</h2>
<p>We fetched <code>wp-admin/includes/class-wp-upgrader.php</code> and <code>wp-admin/includes/update-core.php</code> from the 7.1.3 and 7.1.4 tags of the WordPress/WordPress GitHub mirror and diffed them. Three changes stand out.</p>
<ol>
<li><strong>The staging folder name becomes unguessable.</strong> In 7.1.3, <code>unpack_package()</code> names the working directory after the downloaded package file: <code>$upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' )</code>, inside <code>wp-content/upgrade/</code>. In 7.1.4 a new <code>get_working_dir_name()</code> appends <code>'-' . wp_generate_password( 16, false )</code>.</li>
<li><strong>The upgrade folder can no longer be listed.</strong> 7.1.3 deletes everything in <code>wp-content/upgrade/</code> before unpacking. 7.1.4 skips <code>index.php</code> during that cleanup and writes one if missing, with a comment that the directory &ldquo;is web-served&rdquo; and must not be listed &ldquo;so the name of the working directory created below cannot be discovered from a directory index.&rdquo;</li>
<li><strong>A staged wp-config.php is never copied into the live site.</strong> <code>update_core()</code> in 7.1.4 adds <code>wp-config.php</code> to the list of files it skips when copying the new release over the old one, with the comment &ldquo;Never copy a wp-config.php, which could have been written to the working directory.&rdquo;</li>
</ol>
<p>Read together, the fix closes both halves of the race: finding the staged copy, and turning a file written into it into something that persists after the update. That is our reading of the diff; the CNA&rsquo;s own advisory is the authority on the exploit chain.</p>
<h2 id="why-the-update-itself-is-the-risky-moment">Why the update itself is the risky moment</h2>
<p>The vulnerable step runs in the code that is already installed. When WordPress updates core, <code>Core_Upgrader::upgrade()</code> calls <code>unpack_package()</code> from the running version&rsquo;s <code>WP_Upgrader</code> class, and only then copies the new release&rsquo;s <code>update-core.php</code> into place and runs it. So updating a 7.1.3 site to 7.1.4 stages the 7.1.4 package with the 7.1.3 naming and cleanup logic. The new wp-config.php skip does apply during that update, because it lives in the new <code>update-core.php</code>, but the staging folder is still predictable and listable for that one run.</p>
<p>Two practical consequences:</p>
<ul>
<li><strong>Block the staging path before you update</strong>, not after. A web server rule that refuses every request under <code>/wp-content/upgrade/</code> removes the public half of the race. WordPress writes to that folder through the filesystem, not over HTTP, so it should not need web access to it.</li>
<li><strong>Do not rely on a rule file inside <code>wp-content/upgrade/</code>.</strong> Affected versions delete everything in that folder before unpacking, so a <code>.htaccess</code> placed there is gone when it matters.</li>
</ul>
<p>Illustrative configuration (we did not test these against a live site; adapt paths for subdirectory installs):</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-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#75715e"># nginx, inside the WordPress server block
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">location</span> <span style="color:#e6db74">^~</span> <span style="color:#e6db74">/wp-content/upgrade/</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">deny</span> <span style="color:#e6db74">all</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><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-apache" data-lang="apache"><span style="display:flex;"><span><span style="color:#75715e"># Apache, in the site&#39;s root .htaccess or vhost (mod_alias)</span>
</span></span><span style="display:flex;"><span>RedirectMatch <span style="color:#ae81ff">403</span> ^/wp-content/upgrade/
</span></span></code></pre></div><p>Also check whether automatic updates already did the work. In 7.1.4&rsquo;s <code>Core_Upgrader::should_update_to_version()</code>, the minor auto-update setting reads <code>get_site_option( 'auto_update_core_minor', 'enabled' )</code>, so minor (security) releases install automatically unless the <code>WP_AUTO_UPDATE_CORE</code> constant, a filter or that option turns them off. Many sites will have moved to their branch&rsquo;s fix on their own; managed hosts and fleets that disable auto-updates will not have.</p>
<h2 id="what-to-do-this-week">What to do this week</h2>
<ol>
<li><strong>Inventory versions.</strong> On each site, <code>wp core version</code> (WP-CLI) or <code>wp-includes/version.php</code> gives <code>$wp_version</code>. Anything at or below its branch&rsquo;s &ldquo;last affected&rdquo; row above needs the update. Anything on 4.6 or earlier needs a migration plan.</li>
<li><strong>Block <code>/wp-content/upgrade/</code> at the web server</strong>, reload, and confirm with a request that it returns 403.</li>
<li><strong>Update to 7.1.4</strong>, or to your branch&rsquo;s fixed release if you cannot move to 7.1 yet.</li>
<li><strong>Check for leftovers.</strong> CISA marks this entry for forensic triage. At minimum:</li>
</ol>
<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><span style="color:#75715e"># Run from the WordPress root. Illustrative; adapt the log path.</span>
</span></span><span style="display:flex;"><span>wp core verify-checksums                 <span style="color:#75715e"># core files that differ from the release</span>
</span></span><span style="display:flex;"><span>ls -la wp-content/upgrade/               <span style="color:#75715e"># should be empty apart from index.php after 7.1.4</span>
</span></span><span style="display:flex;"><span>find . -name <span style="color:#e6db74">&#39;wp-config.php&#39;</span> -not -path <span style="color:#e6db74">&#39;./wp-config.php&#39;</span>   <span style="color:#75715e"># unexpected copies</span>
</span></span><span style="display:flex;"><span>grep -E <span style="color:#e6db74">&#39;/wp-content/upgrade/&#39;</span> /var/log/nginx/access.log* | grep -v <span style="color:#e6db74">&#39; 403 &#39;</span>
</span></span></code></pre></div><p>Requests to <code>/wp-content/upgrade/.../setup-config.php</code> or <code>install.php</code> that did not get a 403, especially close to the time of a core update, are the lead to follow. Look for PHP files that <code>verify-checksums</code> does not explain, new administrator accounts, and changes to <code>wp-config.php</code> since the update.</p>
<ol start="5">
<li><strong>Record the decision.</strong> If you track patch decisions as tickets, this is a KEV entry with active exploitation and total technical impact on internet-facing hosts; our <a href="/posts/vulnerability-prioritization-workflow-cve-record-to-patch-ticket/">vulnerability prioritization workflow</a> shows how to carry those signals into the ticket, and <a href="/posts/cisa-kev-json-feed-what-each-field-means-and-how-to-match-it-against-a-scanner-export/">the KEV JSON feed guide</a> explains the <code>dueDate</code> and <code>forensicTriage</code> fields.</li>
</ol>
<h2 id="limits-of-this-article">Limits of this article</h2>
<ul>
<li>We did not reproduce exploitation. The preconditions and the 62,969-attack figure come from Wordfence via The Hacker News; we could not retrieve Wordfence&rsquo;s own advisory page in this run.</li>
<li>Which update package a given site downloads (full, no-content or partial) depends on what the WordPress update API offers it; we did not test which update paths stage the installer files.</li>
<li>The web server rules are illustrative and untested; test them on a staging site first.</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>Description, affected ranges, CVSS 8.1, CWE-367, reporter, published date</td>
          <td><a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/119xxx/CVE-2026-119977.json">CVE-2026-119977 record (cvelistV5)</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>KEV added 3 Nov 2026, due 6 Nov 2026, forensic triage Yes</td>
          <td><a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog">CISA KEV catalog</a> (kev-data JSON, catalog 2026.11.03)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>SSVC active / no / total</td>
          <td>CISA-ADP container in the CVE record</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>7.1.4 release date, fix description, backport versions, support statement</td>
          <td><a href="https://wordpress.org/documentation/?p=16371315">WordPress 7.1.4 release notes</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Fixed release = next point release in all 25 branches</td>
          <td>CVE record vs release notes, our script</td>
          <td>Verified (computed)</td>
      </tr>
      <tr>
          <td>7.1.4 code changes; update runs old staging code</td>
          <td><a href="https://github.com/WordPress/WordPress/tree/7.1.3">WordPress 7.1.3</a> and <a href="https://github.com/WordPress/WordPress/tree/7.1.4">7.1.4</a> source, our diff</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Minor auto-updates on by default</td>
          <td><code>wp-admin/includes/class-core-upgrader.php</code> (7.1.4)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>62,969 blocked attacks in 24 hours; exploitation preconditions</td>
          <td><a href="https://thehackernews.com/2026/10/wordpress-rce-flaw-draws-nearly-63000.html">The Hacker News, 30 Oct 2026</a>, citing Wordfence</td>
          <td>Qualified (press report of vendor telemetry)</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><item><title>VMware ESX CVE-2026-41709: Patch the Logging Gap Now</title><link>https://firewallsync.com/posts/vmware-esx-cve-2026-41709-insufficient-logging-kev/</link><guid>https://firewallsync.com/posts/vmware-esx-cve-2026-41709-insufficient-logging-kev/</guid><pubDate>Sun, 01 Nov 2026 04:30:00 +0000</pubDate><dc:creator>John Marshall</dc:creator><category>Security Operations</category><description>CISA added CVE-2026-41709, a 2.7-rated VMware ESX insufficient-logging flaw, to the KEV catalog on 28 October 2026, three months after Broadcom fixed it in VMSA-2026-0006. A bug that lets an admin act without leaving a log entry matters most after someone else has become that admin. This guide covers the fixed builds, why a Low CVSS score should not decide the priority, and how to make sure ESX logs leave the host.</description><enclosure url="https://firewallsync.com/posts/vmware-esx-cve-2026-41709-insufficient-logging-kev/cover_hu8530406830259982161.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/vmware-esx-cve-2026-41709-insufficient-logging-kev/cover_hu8530406830259982161.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/vmware-esx-cve-2026-41709-insufficient-logging-kev/cover_hu8530406830259982161.jpg" alt="Close-up of dozens of old padlocks, rusted and dust-covered, clustered together with their keyholes facing the camera" width="1200" height="630"></p><p>CVE-2026-41709 is not a bug that lets anyone in. It is a bug that helps whoever is already in avoid being seen. Broadcom fixed it on 29 July 2026 and rated it Low. On 28 October 2026 CISA added it to the Known Exploited Vulnerabilities (KEV) catalog, with a federal due date of 11 November 2026.</p>
<p><strong>The short answer:</strong> update ESX hosts to the fixed build for your branch (ESX 8.0: <code>ESXi80U3j-25429389</code>; 9.0.x: <code>ESXi-9.0.2.0100-25595025</code>; 9.1.x: <code>ESXi-9.1.0.0-25370933</code>), confirm host logs are forwarded to a remote syslog collector, and treat any host that was compromised before patching as having an incomplete audit trail.</p>
<h2 id="what-the-vulnerability-is">What the vulnerability is</h2>
<p>Broadcom&rsquo;s advisory, <a href="https://support.broadcom.com/web/ecx/support-content-notification/-/external/content/SecurityAdvisories/0/38017">VMSA-2026-0006</a> (section 3e), describes it this way: &ldquo;VMware ESX contains an insufficient logging vulnerability.&rdquo; Its known attack vector: &ldquo;A malicious administrator could exploit this issue to perform certain operations without them being logged.&rdquo;</p>
<p>That is the whole public description. Broadcom does not say which operations escape logging, and the CVE record adds nothing beyond the weakness class, CWE-778 (Insufficient Logging). The advisory credits Ian Barton of CrowdStrike with reporting it. We found no public technical write-up or exploitation report as of 1 November 2026, so treat any claim about specific hidden operations with suspicion until Broadcom or the reporter publishes one.</p>
<table>
  <thead>
      <tr>
          <th>Field</th>
          <th>Value</th>
          <th>Source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CVSS 3.1</td>
          <td>2.7 Low, <code>AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N</code></td>
          <td>CVE record (Broadcom CNA)</td>
      </tr>
      <tr>
          <td>Weakness</td>
          <td>CWE-778 Insufficient Logging</td>
          <td>CVE record</td>
      </tr>
      <tr>
          <td>Published</td>
          <td>29 July 2026 (VMSA-2026-0006); CVE record 30 July</td>
          <td>Advisory, CVE record</td>
      </tr>
      <tr>
          <td>KEV added / due</td>
          <td>28 October 2026 / 11 November 2026</td>
          <td>CISA KEV</td>
      </tr>
      <tr>
          <td>Known ransomware use</td>
          <td>Unknown</td>
          <td>CISA KEV</td>
      </tr>
      <tr>
          <td>SSVC (CISA)</td>
          <td>Exploitation: active; Automatable: no; Technical Impact: partial</td>
          <td>CVE record, CISA ADP</td>
      </tr>
      <tr>
          <td>Workaround</td>
          <td>None</td>
          <td>Advisory</td>
      </tr>
  </tbody>
</table>
<h2 id="fixed-builds">Fixed builds</h2>
<p>From the advisory&rsquo;s response matrix, which matches the version ranges in the <a href="https://www.cve.org/CVERecord?id=CVE-2026-41709">CVE record</a>:</p>
<table>
  <thead>
      <tr>
          <th>Product</th>
          <th>Affected</th>
          <th>Fixed version</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>VMware ESX 8.0</td>
          <td>Earlier than the fixed build</td>
          <td><code>ESXi80U3j-25429389</code></td>
      </tr>
      <tr>
          <td>ESX 9.0.x (VCF / vSphere Foundation 9.0)</td>
          <td>Earlier than the fixed build</td>
          <td><code>ESXi-9.0.2.0100-25595025</code></td>
      </tr>
      <tr>
          <td>ESX 9.1.x (VCF / vSphere Foundation 9.1)</td>
          <td>Earlier than the fixed build</td>
          <td><code>ESXi-9.1.0.0-25370933</code></td>
      </tr>
      <tr>
          <td>VMware Cloud Foundation 5.x</td>
          <td>Earlier than 5.2.4</td>
          <td>ESX 5.2.4</td>
      </tr>
      <tr>
          <td>Telco Cloud Platform 5.0.x, 5.1.x</td>
          <td>All</td>
          <td>See Broadcom KB449886</td>
      </tr>
  </tbody>
</table>
<p>The CVE record lists ESX 9.1, 9.0 and 8.0 as affected and gives no ESX 7.0 entry for this CVE. The advisory&rsquo;s August update (VMSA-2026-0006.2) added ESX 7.0 patch guidance for the Critical issues in the same advisory, not for this one.</p>
<p>To compare a host against the table, read its build number. On the host shell, <code>esxcli system version get</code> prints the version, update and build. Match the build number, not just the update name.</p>
<h2 id="why-a-low-score-is-the-wrong-signal-here">Why a Low score is the wrong signal here</h2>
<p>CVSS scores the vulnerability in isolation. &ldquo;Privileges required: high&rdquo; pulls the score down, because an attacker first needs an administrator account. In an intrusion that reaches the hypervisor, the attacker may already have that account, and a way to then act without leaving entries in the host&rsquo;s logs makes the response team&rsquo;s job harder.</p>
<p>CISA lists vulnerabilities in KEV because of evidence of exploitation, not because of their score. Its SSVC entry for this CVE records &ldquo;Exploitation: active&rdquo;. CISA has not published details of the activity, and Broadcom&rsquo;s advisory change log has no entry about exploitation. Our reading, which is interpretation and not a reported fact: this flaw is most likely being used as part of a chain, after an attacker has admin access by other means.</p>
<p>This is the situation <a href="/posts/cvss-vs-epss-vs-kev-which-signal-should-decide-what-you-patch-first/">CVSS vs EPSS vs KEV</a> describes: a KEV listing should outrank a low base score. If you use SSVC, &ldquo;active&rdquo; exploitation with &ldquo;partial&rdquo; technical impact on a hypervisor you depend on usually lands well above routine patching; see <a href="/posts/ssvc-deployer-patch-priority-model-explained-exploitation-exposure-automatable-and-human-impact/">our SSVC deployer walkthrough</a>.</p>
<h2 id="the-vcenter-half-of-the-same-advisory">The vCenter half of the same advisory</h2>
<p>VMSA-2026-0006 also fixed CVE-2026-59310, a vCenter directory-traversal flaw in the syslog server, which CISA added to KEV on 18 August 2026. Many teams patched vCenter quickly in August. ESX host updates are a separate job, usually rolled through clusters host by host, and they are easier to leave half done. If your August change record says &ldquo;VMSA-2026-0006 remediated&rdquo; and only covers vCenter, your hosts may still be on vulnerable builds.</p>
<h2 id="make-the-evidence-leave-the-host">Make the evidence leave the host</h2>
<p>Patching stops the gap from being used from now on. It does not recover entries that were never written, and it does not protect the logs that are written from an admin who can delete them on the host. The control that helps in both cases is shipping logs off the host as they are written.</p>
<p>Broadcom&rsquo;s KB <a href="https://knowledge.broadcom.com/external/article/318939/configuring-syslog-on-esxi.html">Configuring syslog on ESXi</a> notes that &ldquo;by default in ESXi, these logs are placed on a local scratch volume or a ramdisk.&rdquo; Its commands for sending them to a remote collector:</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-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#75715e"># On the ESXi host shell (per Broadcom KB 318939). Replace the address.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Supported loghost formats include udp://host:514, tcp://host:514 and ssl://host:1514.</span>
</span></span><span style="display:flex;"><span>esxcli system syslog config set --loghost<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;ssl://syslog.example.internal:1514&#39;</span>
</span></span><span style="display:flex;"><span>esxcli system syslog reload
</span></span><span style="display:flex;"><span>esxcli network firewall ruleset set --ruleset-id<span style="color:#f92672">=</span>syslog --enabled<span style="color:#f92672">=</span>true
</span></span><span style="display:flex;"><span>esxcli network firewall refresh
</span></span></code></pre></div><p>We have not run these commands on a host; they are quoted from the KB. Prefer <code>ssl://</code> where your collector supports it, set the same value through host profiles or your configuration tool so it does not drift, and alert when a host stops sending.</p>
<p>Broadcom&rsquo;s <a href="https://knowledge.broadcom.com/external/article/306962/location-of-esxi-log-files.html">log file reference</a> lists the files worth prioritising on the collector:</p>
<table>
  <thead>
      <tr>
          <th>File</th>
          <th>What Broadcom says it contains</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>shell.log</code></td>
          <td>&ldquo;ESXi Shell usage logs, including enable/disable and every command entered&rdquo;</td>
      </tr>
      <tr>
          <td><code>auth.log</code></td>
          <td>&ldquo;ESXi Shell authentication success and failure&rdquo;</td>
      </tr>
      <tr>
          <td><code>hostd.log</code></td>
          <td>&ldquo;Host management service logs, including virtual machine and host Task and Events, communication with the vSphere Client&rdquo;</td>
      </tr>
      <tr>
          <td><code>vpxa.log</code></td>
          <td>&ldquo;vCenter Server vpxa agent logs, including communication with vCenter Server and the Host Management hostd agent&rdquo;</td>
      </tr>
      <tr>
          <td><code>syslog.log</code></td>
          <td>&ldquo;Management service initialization, watchdogs, scheduled tasks and DCUI use&rdquo;</td>
      </tr>
      <tr>
          <td><code>vobd.log</code></td>
          <td>&ldquo;VMkernel Observation events&rdquo;</td>
      </tr>
  </tbody>
</table>
<p>Because Broadcom has not said which operations escape logging, you cannot write a detection for the missing entries themselves. What you can do is cross-check sources that an ESX-local gap would not touch: vCenter tasks and events, your collector&rsquo;s copy of the host logs, and changes visible from outside the host (new VMs, changed datastores, powered-off guests). <a href="/posts/logging-for-incidents-not-for-dashboards/">Logging for incidents, not for dashboards</a> covers how to decide what to keep and for how long.</p>
<h2 id="what-to-do-this-week">What to do this week</h2>
<ol>
<li>Inventory every ESX host and its build number; compare against the fixed-version table.</li>
<li>Patch hosts still below the fixed build. There is no workaround.</li>
<li>Confirm each host has a remote <code>loghost</code> set and that the collector has recent entries from it.</li>
<li>If a host was compromised, or admin credentials for it were exposed, before it was patched, record that its local logs may be incomplete for that period and lean on vCenter and remote copies for the investigation.</li>
<li>US federal civilian agencies: the KEV due date is 11 November 2026, with the <a href="/posts/cisa-bod-26-04-explained-kev-deadlines-forensic-triage-and-what-private-teams-can-borrow/">BOD 26-04</a> requirements CISA attaches to the entry. The KEV entry&rsquo;s forensic triage flag is &ldquo;No&rdquo;.</li>
</ol>
<h2 id="limits-of-this-article">Limits of this article</h2>
<p>Broadcom has not published which operations go unlogged, and CISA has not published the exploitation evidence behind the KEV listing. We have not tested the vulnerability or the fix. The esxcli commands are quoted from Broadcom&rsquo;s knowledge base, not run by us. Check Broadcom&rsquo;s advisory for updates before you rely on the fixed-version table.</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>Description, CVSS 2.7, fixed versions, no workaround, CrowdStrike credit, change log</td>
          <td><a href="https://support.broadcom.com/web/ecx/support-content-notification/-/external/content/SecurityAdvisories/0/38017">Broadcom VMSA-2026-0006</a> (last updated 19 Aug 2026)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Affected version ranges, CWE-778, CISA SSVC values</td>
          <td><a href="https://www.cve.org/CVERecord?id=CVE-2026-41709">CVE-2026-41709 record</a> (CVEProject cvelistV5, updated 29 Oct 2026)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>KEV dates added and due, ransomware &ldquo;Unknown&rdquo;, forensic triage &ldquo;No&rdquo;</td>
          <td><a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog">CISA KEV catalog</a> (cisagov/kev-data, version 2026.10.30)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CVE-2026-59310 in KEV on 18 Aug 2026</td>
          <td>CISA KEV catalog</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Syslog commands and loghost formats</td>
          <td><a href="https://knowledge.broadcom.com/external/article/318939/configuring-syslog-on-esxi.html">Broadcom KB 318939</a></td>
          <td>Verified (no version range stated on the KB)</td>
      </tr>
      <tr>
          <td>Log file contents</td>
          <td><a href="https://knowledge.broadcom.com/external/article/306962/location-of-esxi-log-files.html">Broadcom KB 306962</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Exploitation used to hide post-compromise activity</td>
          <td>Editorial interpretation</td>
          <td>Qualified</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>Ivanti CVE-2026-111357 and CVE-2026-118527: What to Do</title><link>https://firewallsync.com/posts/ivanti-connect-secure-cve-2026-111357-cve-2026-118527-kev/</link><guid>https://firewallsync.com/posts/ivanti-connect-secure-cve-2026-111357-cve-2026-118527-kev/</guid><pubDate>Sat, 31 Oct 2026 05:00:00 +0000</pubDate><dc:creator>John Marshall</dc:creator><category>Security Operations</category><description>CISA added two more Ivanti Connect Secure flaws to KEV on 30 October: CVE-2026-111357, a privilege escalation to root, and CVE-2026-118527, a predictable-identifier bug that lets an authenticated attacker write files to a known path. Both chain with CVE-2026-104935, the authentication bypass Ivanti patched on 13 October. Here is what the public records confirm, what they do not, and what to do before the 2 November KEV deadline.</description><enclosure url="https://firewallsync.com/posts/ivanti-connect-secure-cve-2026-111357-cve-2026-118527-kev/cover_hu10585840409955398963.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/ivanti-connect-secure-cve-2026-111357-cve-2026-118527-kev/cover_hu10585840409955398963.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/ivanti-connect-secure-cve-2026-111357-cve-2026-118527-kev/cover_hu10585840409955398963.jpg" alt="Close-up of three thick, rusty steel chain links, the nearest in sharp focus and the rest fading into a blurred grey background" width="1200" height="630"></p><p>If you run Ivanti Connect Secure, the job this weekend is the same as two weeks ago, only with less room for doubt. On 30 October 2026 CISA added two more Connect Secure flaws to its <a href="https://github.com/cisagov/kev-data">Known Exploited Vulnerabilities catalog</a>: <strong>CVE-2026-111357</strong>, a privilege escalation to root, and <strong>CVE-2026-118527</strong>, a predictable-identifier bug that lets an authenticated attacker write files to a known location on disk. KEV says both chain with <strong>CVE-2026-104935</strong>, the authentication bypass Ivanti patched on 13 October.</p>
<p>Upgrade to a release that fixes CVE-2026-104935 if you have not already. Then treat any appliance that was exposed on 22.8R2.4 or earlier during October as a possible compromise. As of 31 October we could not find a public fixed version for either of the two new CVEs, and the sections below explain why.</p>
<h2 id="the-three-cves-in-the-chain">The three CVEs in the chain</h2>
<table>
  <thead>
      <tr>
          <th></th>
          <th>CVE-2026-104935</th>
          <th>CVE-2026-118527</th>
          <th>CVE-2026-111357</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>What KEV calls it</td>
          <td>Authentication bypass by spoofing</td>
          <td>Generation of predictable numbers or identifiers</td>
          <td>Missing authentication for critical function</td>
      </tr>
      <tr>
          <td>Attacker position (KEV text)</td>
          <td>Remote, unauthenticated</td>
          <td>Remote, authenticated</td>
          <td>Local, authenticated</td>
      </tr>
      <tr>
          <td>Effect (KEV / CVE text)</td>
          <td>Execute arbitrary commands</td>
          <td>Upload files with attacker-controlled content to a known location on disk</td>
          <td>Privilege escalation; the CVE record says &ldquo;to root&rdquo;</td>
      </tr>
      <tr>
          <td>CWE</td>
          <td>CWE-290</td>
          <td>CWE-340</td>
          <td>KEV: CWE-306, CWE-862, CWE-345. CVE record: CWE-829</td>
      </tr>
      <tr>
          <td>Added to KEV</td>
          <td>2026-10-13</td>
          <td>2026-10-30</td>
          <td>2026-10-30</td>
      </tr>
      <tr>
          <td>KEV due date</td>
          <td>2026-10-16</td>
          <td>2026-11-13</td>
          <td>2026-11-02</td>
      </tr>
      <tr>
          <td>KEV forensic triage</td>
          <td>Yes</td>
          <td>No</td>
          <td>Yes</td>
      </tr>
      <tr>
          <td>CVE record</td>
          <td>Published by Ivanti, CVSS 3.1 8.6</td>
          <td>No published record found on 31 Oct</td>
          <td>Published by MITRE, CVSS 3.1 7.0</td>
      </tr>
  </tbody>
</table>
<p>The KEV entries for CVE-2026-118527 and CVE-2026-111357 both say the flaw &ldquo;can be chained with&rdquo; the other two. Read together, the descriptions fit a familiar pattern: an unauthenticated foothold, a way to place attacker-controlled content where the appliance will find it, then a jump to root. That ordering is our reading of the descriptions. Neither Ivanti nor CISA has published the step-by-step mechanics.</p>
<p>The MITRE record for CVE-2026-111357 adds one technical detail. It says Connect Secure 22.8R2.4 &ldquo;mishandles the manner in which the dsinvoked broker trusts DSCache configuration data, leading to privilege escalation to root, as exploited in the wild in October 2026.&rdquo;</p>
<p>If you track these programmatically, this pulls the three entries from CISA&rsquo;s KEV JSON. We ran it with Python 3.13 on 31 October; it uses only the standard library:</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:#f92672">import</span> json<span style="color:#f92672">,</span> urllib.request
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>URL <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https://raw.githubusercontent.com/cisagov/kev-data/main/known_exploited_vulnerabilities.json&#34;</span>
</span></span><span style="display:flex;"><span>WANT <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#34;CVE-2026-104935&#34;</span>, <span style="color:#e6db74">&#34;CVE-2026-118527&#34;</span>, <span style="color:#e6db74">&#34;CVE-2026-111357&#34;</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">with</span> urllib<span style="color:#f92672">.</span>request<span style="color:#f92672">.</span>urlopen(URL, timeout<span style="color:#f92672">=</span><span style="color:#ae81ff">30</span>) <span style="color:#66d9ef">as</span> r:
</span></span><span style="display:flex;"><span>    kev <span style="color:#f92672">=</span> json<span style="color:#f92672">.</span>load(r)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> v <span style="color:#f92672">in</span> kev[<span style="color:#e6db74">&#34;vulnerabilities&#34;</span>]:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> v[<span style="color:#e6db74">&#34;cveID&#34;</span>] <span style="color:#f92672">in</span> WANT:
</span></span><span style="display:flex;"><span>        print(v[<span style="color:#e6db74">&#34;cveID&#34;</span>], v[<span style="color:#e6db74">&#34;dateAdded&#34;</span>], v[<span style="color:#e6db74">&#34;dueDate&#34;</span>],
</span></span><span style="display:flex;"><span>              <span style="color:#e6db74">&#34;triage=&#34;</span> <span style="color:#f92672">+</span> v<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;forensicTriage&#34;</span>, <span style="color:#e6db74">&#34;?&#34;</span>), <span style="color:#e6db74">&#34;,&#34;</span><span style="color:#f92672">.</span>join(v[<span style="color:#e6db74">&#34;cwes&#34;</span>]))
</span></span></code></pre></div><p>Output on 31 October:</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-118527 2026-10-30 2026-11-13 triage=No CWE-340
</span></span><span style="display:flex;"><span>CVE-2026-111357 2026-10-30 2026-11-02 triage=Yes CWE-306,CWE-862,CWE-345
</span></span><span style="display:flex;"><span>CVE-2026-104935 2026-10-13 2026-10-16 triage=Yes CWE-290
</span></span></code></pre></div><p>For what each field means and how to match the feed against a scanner export, see our guide to 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>.</p>
<h2 id="what-is-fixed-and-what-is-not">What is fixed and what is not</h2>
<p><strong>CVE-2026-104935 has fixes.</strong> The CVE record Ivanti published says the bug affects &ldquo;ICS before version 25.1.3.0&rdquo; and &ldquo;does not impact ICS version 22.7R2.14 or prior&rdquo;. It lists 25.1.3.0, 25.1.3.1, 22.8R2.5 and 22.7R2.14 as unaffected.</p>
<p>Rapid7&rsquo;s write-up of Ivanti&rsquo;s advisory breaks this down by branch: 25.1.1.1 and earlier fixed in 25.1.1.2, 25.1.2.2 and earlier fixed in 25.1.3.0 and 25.1.3.1, and 22.8R2.4 and earlier fixed in 22.8R2.5. The 25.1.1.2 entry does not appear in the CVE record&rsquo;s unaffected list, so confirm it against <a href="https://hub.ivanti.com/s/article/Security-Advisory-Ivanti-Connect-Secure-CVE-2026-104935">Ivanti&rsquo;s advisory</a> before you rely on it.</p>
<p><strong>CVE-2026-111357 and CVE-2026-118527 have no fixed version that we could confirm.</strong> When Ivanti disclosed CVE-2026-104935 on 13 October, it fixed two stages of the chain. <a href="https://www.theregister.com/a/5303095">The Register</a> and <a href="https://thehackernews.com/2026/10/attacker-chains-three-ivanti-connect.html">The Hacker News</a> both reported that a third flaw, the privilege escalation, had no fix yet, and quoted Volexity saying Ivanti planned to fix it &ldquo;in the coming weeks&rdquo;.</p>
<p>Since then:</p>
<ul>
<li>The only CVE record for CVE-2026-111357 is MITRE&rsquo;s. It lists 22.8R2.4 as affected and gives no fixed version. Its references are Volexity&rsquo;s report and Ivanti&rsquo;s CVE-2026-104935 advisory, not a separate Ivanti advisory.</li>
<li>CVE-2026-118527 had no record in the CVE List repository when we checked on 31 October. Its KEV entry is the only primary description we found.</li>
<li>Both KEV entries list Ivanti&rsquo;s CVE-2026-104935 advisory as the vendor reference, and both carry CISA&rsquo;s standard required action: apply vendor mitigations, or &ldquo;discontinue use of the product if mitigations are unavailable&rdquo;.</li>
<li>Canada&rsquo;s Cyber Centre updated its advisory on 16 October to say open-source reporting indicates CVE-2026-111357 is exploited. Singapore&rsquo;s CSA alert, last updated 30 October, still names only CVE-2026-104935 and advises updating &ldquo;to the latest versions&rdquo;.</li>
</ul>
<p>We could not read Ivanti&rsquo;s advisory directly during this run, and Ivanti may have published a fix that these records do not yet reflect. Check the advisory and Ivanti&rsquo;s support portal before you decide that your current version is enough.</p>
<h2 id="why-228r24-matters">Why 22.8R2.4 matters</h2>
<p>According to The Hacker News&rsquo;s summary of Volexity&rsquo;s report, Volexity found the chain on a customer appliance running 22.8R2.4, which was fully patched at the time. That is the exact version MITRE&rsquo;s CVE-2026-111357 record lists as affected. Exploitation began on 3 October, ten days before disclosure.</p>
<p>Volexity tracks the actor as UTA0576. The same reports say the attacker:</p>
<ul>
<li>stole LDAP domain credentials from the appliance, searched Active Directory for passwords and ran password-spraying attacks;</li>
<li>used no malware or web shells, only commands already on the appliance (per The Register);</li>
<li>was assessed by Volexity, with low confidence, as criminally rather than espionage motivated.</li>
</ul>
<p>Two vendor statements limit how much you can learn from the appliance itself. Rapid7 quotes Ivanti saying &ldquo;reliable indicators of compromise are not available&rdquo;. The Hacker News reports Volexity saying the Ivanti Integrity Checker Tool does not detect this chain, even though Ivanti still recommends running it regularly.</p>
<h2 id="triage-checklist">Triage checklist</h2>
<ol>
<li><strong>Inventory.</strong> List every Connect Secure appliance and its exact version, including standby units and lab boxes that face the internet.</li>
<li><strong>Close the entry point.</strong> Upgrade anything below the fixed versions for CVE-2026-104935 (see above). This is the unauthenticated step. KEV describes the other two flaws as needing an authenticated or local attacker.</li>
<li><strong>Assume compromise on exposed 22.8R2.4-and-earlier appliances.</strong> If an appliance ran a vulnerable version on the internet during October, patching does not undo what an attacker already did. Neither Ivanti nor Volexity has said that upgrading removes existing access.</li>
<li><strong>Rotate what the appliance knows.</strong> Volexity saw LDAP credentials stolen. Rotate the directory bind account and any other service credentials stored on the appliance, and review VPN user sessions and tokens. This is our recommendation, based on the reported attacker behavior. Our explainer on <a href="/posts/what-is-token-theft-and-why-mfa-doesnt-always-stop-it/">why MFA does not always stop token theft</a> covers the session side.</li>
<li><strong>Hunt outside the appliance.</strong> With no reliable on-box IOCs, the useful signals are in your other logs:
<ul>
<li>password spraying or bursts of failed authentications from the appliance&rsquo;s internal IP against Active Directory;</li>
<li>LDAP queries from the appliance that go beyond its normal user lookups;</li>
<li>in web or WAF logs in front of the appliance, large numbers of requests to <code>/dana-na/auth/url_default/welcome.cgi</code>, and requests whose <code>X-DSCGI-PATH</code> header does not match the URL path (both indicators Volexity published, as reported by The Hacker News);</li>
<li>traffic to or from <code>108.165.147[.]64</code>, the IP Volexity listed.</li>
</ul>
</li>
<li><strong>Escalate to forensics if you find anything.</strong> Volexity says confirming compromise needs network and memory forensics. Our guide to <a href="/posts/cisa-bod-26-04-explained-kev-deadlines-forensic-triage-and-what-private-teams-can-borrow/">CISA BOD 26-04</a> explains what the KEV &ldquo;forensic triage&rdquo; flag asks of federal agencies and what private teams can borrow from it.</li>
<li><strong>Decide on exposure while you wait.</strong> Until a fix for CVE-2026-111357 is confirmed, limit who can reach the appliance where you can. KEV&rsquo;s own fallback is to stop using the product if mitigations are unavailable. Our post on the <a href="/posts/fortimail-zero-day-cve-2026-104286-no-patch-yet-what-to-do/">FortiMail zero-day with no patch</a> walks through the same decision for another edge device.</li>
</ol>
<h2 id="limits-of-this-article">Limits of this article</h2>
<ul>
<li>We did not test any of these flaws, and we have not seen exploit code.</li>
<li>We could not fetch Ivanti&rsquo;s advisory or Volexity&rsquo;s report directly. Version and fix details come from the CVE records, CISA KEV data and Rapid7&rsquo;s reproduction of the advisory. Attacker behavior and indicators come from press summaries of Volexity&rsquo;s findings, which we attribute throughout.</li>
<li>CVE-2026-118527 had no CVE record when we checked, so its description rests on one source, CISA&rsquo;s KEV entry.</li>
<li>Fix status can change quickly. Treat &ldquo;no confirmed fix&rdquo; as true for 31 October 2026 only.</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>KEV additions, dates, due dates, CWEs, forensic triage, &ldquo;can be chained with&rdquo;, required action</td>
          <td><a href="https://github.com/cisagov/kev-data/blob/main/known_exploited_vulnerabilities.json">CISA KEV catalog (kev-data)</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CVE-2026-104935 description, unaffected versions, CVSS 8.6, CISA SSVC &ldquo;active&rdquo;</td>
          <td><a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/104xxx/CVE-2026-104935.json">CVE-2026-104935 record</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CVE-2026-111357 description (dsinvoked, DSCache, root), affected 22.8R2.4, CVSS 7.0, MITRE as CNA</td>
          <td><a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/111xxx/CVE-2026-111357.json">CVE-2026-111357 record</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Per-branch fixed versions including 25.1.1.2; Ivanti: &ldquo;reliable indicators of compromise are not available&rdquo;</td>
          <td><a href="https://www.rapid7.com/blog/post/etr-ivanti-connect-secure-zero-day-exploited-in-the-wild-cve-2026-104935/">Rapid7</a></td>
          <td>Qualified (secondary)</td>
      </tr>
      <tr>
          <td>Third flaw unfixed at disclosure; Volexity on 22.8R2.4, UTA0576, LDAP theft, indicators, Integrity Checker gap</td>
          <td><a href="https://thehackernews.com/2026/10/attacker-chains-three-ivanti-connect.html">The Hacker News</a>, <a href="https://www.theregister.com/a/5303095">The Register</a></td>
          <td>Qualified (press, citing Volexity)</td>
      </tr>
      <tr>
          <td>CVE-2026-111357 reported exploited (update of 16 Oct)</td>
          <td><a href="https://cyber.gc.ca/en/alerts-advisories/ivanti-security-advisory-av26-1035">Canadian Centre for Cyber Security AV26-1035</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Singapore alert names only CVE-2026-104935 (updated 30 Oct)</td>
          <td><a href="https://www.csa.gov.sg/alerts-and-advisories/alerts/al-2026-147/">CSA Singapore AL-2026-147</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>No public fix for CVE-2026-111357 or CVE-2026-118527</td>
          <td>Absence across the sources above</td>
          <td>Qualified</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>BeyondTrust CVE-2026-102764: Patch, Then Hunt for SAWFLY</title><link>https://firewallsync.com/posts/beyondtrust-remote-support-cve-2026-102764-patch-and-hunt/</link><guid>https://firewallsync.com/posts/beyondtrust-remote-support-cve-2026-102764-patch-and-hunt/</guid><pubDate>Thu, 22 Oct 2026 18:41:00 +0000</pubDate><dc:creator>Craig Leslie</dc:creator><category>Security Operations</category><description>A BeyondTrust Remote Support authentication bypass was exploited as a zero-day from late August 2026. SaaS instances are patched; self-hosted appliances need the BT26-05-RS patch, and patching does not remove an attacker who is already in. Here is what to patch, what to hunt for and what to rotate.</description><enclosure url="https://firewallsync.com/posts/beyondtrust-remote-support-cve-2026-102764-patch-and-hunt/cover_hu10350490808426910252.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/beyondtrust-remote-support-cve-2026-102764-patch-and-hunt/cover_hu10350490808426910252.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/beyondtrust-remote-support-cve-2026-102764-patch-and-hunt/cover_hu10350490808426910252.jpg" alt="A bright, empty data centre hall with black and white equipment cabinets under overhead trays of blue network cables" width="1200" height="630"></p><p>BeyondTrust Remote Support appliances running version 26.2.3 or earlier have an authentication bypass, CVE-2026-102764, that was exploited as a zero-day for about six weeks before it was disclosed. If you run a self-hosted appliance, apply the BT26-05-RS patch now. Then assume the appliance may have been compromised and check it, because the actor behind the attacks installed a web shell, a tunnel and a root backdoor that a patch does not remove.</p>
<p><strong>Scope.</strong> On October 22, 2026 we read the CVE record, the KEV catalog (version 2026.10.21), BeyondTrust&rsquo;s blog post on BT26-05 (last updated October 16), Google Threat Intelligence Group&rsquo;s analysis, the Canadian Centre for Cyber Security&rsquo;s alert AL26-025 and Rapid7&rsquo;s analysis. BeyondTrust&rsquo;s advisory page for BT26-05 did not load for us, so patch and version details below come from the CVE record, the Cyber Centre and Google, and we say so where it matters. We did not test the vulnerability.</p>
<h2 id="the-vulnerability">The vulnerability</h2>
<p>The CVE record, published by BeyondTrust on October 15, 2026, says internal components of Remote Support &ldquo;did not adequately validate the origin of the messages it received&rdquo;, which &ldquo;could allow an attacker to perform file operations on the appliance&rdquo;. It is classified as CWE-290, authentication bypass by spoofing, and affects Remote Support versions up to and including 26.2.3.</p>
<p>BeyondTrust scores it CVSS 4.0 9.3 (<code>AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H</code>): reachable over the network, no privileges, no user interaction. CISA&rsquo;s enrichment in the record rates it exploitation active, automatable yes, technical impact total. The Cyber Centre describes the impact as unauthorized file operations &ldquo;including arbitrary file uploads, potentially leading to full appliance compromise&rdquo;.</p>
<p>That combination matters more than the score. Remote Support appliances sit at the edge, broker privileged sessions into internal systems and can store credentials. An unauthenticated file upload on such a device is a direct path to the systems it administers.</p>
<h2 id="timeline">Timeline</h2>
<table>
  <thead>
      <tr>
          <th>Date (2026)</th>
          <th>Event</th>
          <th>Source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>August 29</td>
          <td>The zero-day is used against one BeyondTrust-hosted Remote Support instance and one self-hosted appliance</td>
          <td>BeyondTrust; Google says &ldquo;late August&rdquo;</td>
      </tr>
      <tr>
          <td>September 28</td>
          <td>BeyondTrust finds activity on the hosted instance and contains it, it says within 27 minutes of first detection</td>
          <td>BeyondTrust</td>
      </tr>
      <tr>
          <td>September 30</td>
          <td>Mandiant shares findings from the self-hosted customer&rsquo;s investigation</td>
          <td>BeyondTrust</td>
      </tr>
      <tr>
          <td>October 8</td>
          <td>Patch released to SaaS and self-hosted customers</td>
          <td>BeyondTrust</td>
      </tr>
      <tr>
          <td>October 9</td>
          <td>SaaS tenants patched</td>
          <td>Google, Canadian Cyber Centre</td>
      </tr>
      <tr>
          <td>October 15</td>
          <td>Coordinated disclosure: CVE, BeyondTrust blog, Google analysis</td>
          <td>CVE record, BeyondTrust, Google</td>
      </tr>
      <tr>
          <td>October 16</td>
          <td>CISA adds the CVE to KEV; due date October 19; forensic triage required</td>
          <td>KEV catalog</td>
      </tr>
  </tbody>
</table>
<p>As of its last update on October 16, BeyondTrust said it knew of only those two affected customers and had seen no adversary activity since August. That is a statement about what BeyondTrust has observed, not a guarantee about every appliance.</p>
<h2 id="what-to-patch">What to patch</h2>
<table>
  <thead>
      <tr>
          <th>Deployment</th>
          <th>Action</th>
          <th>Source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Remote Support SaaS</td>
          <td>No patch action; BeyondTrust says SaaS was patched automatically</td>
          <td>BeyondTrust, Cyber Centre, Google</td>
      </tr>
      <tr>
          <td>Self-hosted Remote Support 24.3.1 to 26.2.3</td>
          <td>Apply the BT26-05-RS patch (Google says from the <code>/appliance</code> interface)</td>
          <td>Cyber Centre, Google</td>
      </tr>
      <tr>
          <td>Self-hosted Remote Support older than 24.3.1</td>
          <td>Upgrade to a supported version, then apply the patch</td>
          <td>Cyber Centre, Google</td>
      </tr>
      <tr>
          <td>Self-hosted Privileged Remote Access</td>
          <td>Apply BeyondTrust&rsquo;s precautionary PRA patch; BeyondTrust found no exploit path in PRA</td>
          <td>BeyondTrust; Rapid7 says confirm the right patch with BeyondTrust Support</td>
      </tr>
  </tbody>
</table>
<p>The Cyber Centre also advises checking that automatic updates are enabled where appropriate. If you have more than one appliance, inventory them first; a forgotten secondary or lab instance is a common gap.</p>
<h2 id="what-the-attackers-did">What the attackers did</h2>
<p>Google Threat Intelligence Group attributes the exploitation to ARMORY CASTLE, &ldquo;a suspected PRC-nexus espionage threat actor (formerly tracked as UNC5221)&rdquo;. BeyondTrust attributes it, with moderate to high confidence, to the same group under its earlier name. Google&rsquo;s analysis describes:</p>
<ul>
<li><strong>SAWFLY</strong>, an obfuscated PHP web shell named <code>mangoapi.php</code>, placed under the appliance&rsquo;s Laravel <code>public</code> directory, that returns HTTP 404 unless a specific POST parameter (<code>_c94mfe</code>) is present.</li>
<li><strong>BARECLAW</strong>, a tunneler at <code>/tmp/ingredi_ws</code> providing a SOCKS5 proxy over WebSocket, listening on local TCP port 19800 and exposed through an added HAProxy route, <code>/uidchanarge</code>, in <code>/ns/config/haproxy.conf</code>.</li>
<li>A copy of <code>/bin/sh</code> at <code>/usr/bin/dbus-authd</code>, owned by root with the SUID bit set.</li>
<li>Persistence through <code>/home/bomgar/sbin/post_boot.d/zz-root-persist</code>, which adds a passwordless sudo rule to <code>/ns/config/sudoers.template</code> and rebuilds <code>/etc/sudoers</code>.</li>
<li>Deletion of logs on the appliance.</li>
</ul>
<p>Google publishes these SHA-256 hashes:</p>
<table>
  <thead>
      <tr>
          <th>File</th>
          <th>SHA-256</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>mangoapi.php</code> (SAWFLY)</td>
          <td><code>dc14e215269a93fdbc4c1a80b984c23faf7af0911c6dbb85309796a6f2ae95fb</code></td>
      </tr>
      <tr>
          <td><code>ingredi_ws</code> (BARECLAW)</td>
          <td><code>1f19b9a27d79c11bda00a1e8faf74a7fdd683d38ccef1b60df2fd0307e3aa462</code></td>
      </tr>
  </tbody>
</table>
<p>Rapid7 notes that customers cannot audit the appliance&rsquo;s host file system directly and should coordinate host-level inspection with BeyondTrust Support. BeyondTrust offers a threat-hunting package through its trust portal.</p>
<h2 id="how-to-hunt-without-relying-on-hashes">How to hunt without relying on hashes</h2>
<p>BeyondTrust warns that indicators from one victim &ldquo;rarely reappear at the next&rdquo; and that evidence stored only on the appliance may be missing or manipulated. Its blog and Google&rsquo;s analysis suggest hunting for behavior instead:</p>
<ul>
<li>Successful <code>/login</code> sessions from residential broadband or commercial VPN addresses, or outside business hours.</li>
<li><code>user_changed</code> events that raise Jump Item or team roles, and any unauthorized changes to accounts, permissions or session policies.</li>
<li>Requests to unknown <code>.php</code> paths, and WebSocket upgrades from unexpected sources.</li>
<li>Web service accounts spawning shells.</li>
<li>Gaps in syslog forwarding, especially gaps that start and end within one session.</li>
</ul>
<p>The last one depends on external logs. If the appliance does not already forward syslog and session events to a SIEM, BeyondTrust&rsquo;s advice is to start now; as Rapid7 points out, logging enabled today cannot recover evidence that was already deleted.</p>
<h2 id="if-an-appliance-may-be-compromised">If an appliance may be compromised</h2>
<p>Google&rsquo;s recommended order, condensed:</p>
<ol>
<li><strong>Preserve evidence first.</strong> Snapshot virtual appliances with memory, and collect syslog, reverse-proxy or WAF and firewall logs before reboots or changes.</li>
<li><strong>Contain.</strong> Block inbound traffic at the perimeter, restrict egress, end sessions, and disable, rather than delete, Jump Clients, Jumpoints and API accounts.</li>
<li><strong>Rebuild rather than clean.</strong> Redeploy from a clean, patched image, and restore only configuration backups from before the exposure window.</li>
<li><strong>Rotate credentials after patching or rebuilding</strong>, in dependency order: credentials in the vault and Password Safe, and any credential typed into a support session during the window. BeyondTrust adds: watch for unmanaged logins and review new MFA registrations on privileged accounts.</li>
<li><strong>Restrict the admin interfaces.</strong> Limit <code>/login</code> and <code>/appliance</code> by IP and require single sign-on with phishing-resistant MFA.</li>
</ol>
<p>If you find evidence of exploitation, BeyondTrust asks customers to open a severity 1 support case citing BT26-05.</p>
<p>For federal agencies, the KEV due date was October 19 and forensic triage is required; <a href="/posts/cisa-bod-26-04-explained-kev-deadlines-forensic-triage-and-what-private-teams-can-borrow/">our BOD 26-04 explainer</a> covers what that triage involves and what private teams can borrow from it. For how a KEV listing should outrank a score when you prioritize, see <a href="/posts/cvss-vs-epss-vs-kev-which-signal-should-decide-what-you-patch-first/">CVSS vs EPSS vs KEV</a>.</p>
<h2 id="limits-of-this-article">Limits of this article</h2>
<p>BeyondTrust&rsquo;s BT26-05 advisory page did not load for us; we relied on its blog post, the CVE record, Google and the Canadian Cyber Centre for versions and patch names. Rapid7&rsquo;s article is a secondary source and is used only for statements it attributes to BeyondTrust or Mandiant and for its own clearly labelled advice. Attribution and indicators are Google&rsquo;s and BeyondTrust&rsquo;s; we have not verified them. Details may change as the vendors update their guidance.</p>
<h2 id="sources-and-verification">Sources and verification</h2>
<p>Checked on October 22, 2026.</p>
<table>
  <thead>
      <tr>
          <th>Important claim</th>
          <th>Source</th>
          <th>Verification</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Description, CWE-290, affected up to 26.2.3, CVSS 4.0 9.3 and vector, published October 15</td>
          <td><a href="https://www.cve.org/CVERecord?id=CVE-2026-102764">CVE-2026-102764 record</a> (read via the cvelistV5 repository)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CISA SSVC: exploitation active, automatable, total impact</td>
          <td>CISA-ADP container in the CVE record</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>KEV: added October 16, due October 19, forensic triage Yes</td>
          <td><a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog">CISA KEV catalog</a>, version 2026.10.21</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Timeline (August 29 to October 15), two affected customers, PRA precautionary patch, SaaS auto-patched, hunting behaviors, rotation advice, Sev 1 case</td>
          <td><a href="https://beyondtrust.com/blog/entry/bt26-05">BeyondTrust: ARMORY CASTLE and BT26-05</a></td>
          <td>Verified against the vendor&rsquo;s blog</td>
      </tr>
      <tr>
          <td>Attribution, malware names, file paths, HAProxy route, hashes, response steps</td>
          <td><a href="https://cloud.google.com/blog/topics/threat-intelligence/armory-castle-exploits-beyondtrust">Google Threat Intelligence: ARMORY CASTLE Exploits BeyondTrust</a></td>
          <td>Qualified: Google&rsquo;s analysis, not independently verified</td>
      </tr>
      <tr>
          <td>BT26-05-RS patch for 24.3.1 to 26.2.3; upgrade first if older; SaaS patched October 9</td>
          <td><a href="https://cyber.gc.ca/en/alerts-advisories/al26-025-critical-vulnerability-impacting-beyondtrust-remote-support-cve-2026-102764">Canadian Centre for Cyber Security alert AL26-025</a> and Google</td>
          <td>Verified across two sources</td>
      </tr>
      <tr>
          <td>Host file system can&rsquo;t be audited directly; logs enabled now can&rsquo;t recover deleted evidence</td>
          <td><a href="https://www.rapid7.com/blog/post/etr-cve-2026-102764-critical-beyondtrust-remote-support-authentication-bypass-exploited-in-the-wild">Rapid7 analysis</a></td>
          <td>Qualified: secondary source</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>Plex Media Server CVE-2026-96656 Chain: Patch and Hunt</title><link>https://firewallsync.com/posts/plex-media-server-cve-2026-96656-exploited-chain-patch-and-hunt/</link><guid>https://firewallsync.com/posts/plex-media-server-cve-2026-96656-exploited-chain-patch-and-hunt/</guid><pubDate>Thu, 22 Oct 2026 18:40:00 +0000</pubDate><dc:creator>John Marshall</dc:creator><category>Security Operations</category><description>Four Plex Media Server flaws fixed in 1.43.3.10861 are now in CISA's KEV catalog, and Plex says the chain is being widely exploited after a public proof of concept. Here is what each CVE does, which deadlines apply, and what to check if your server was exposed.</description><enclosure url="https://firewallsync.com/posts/plex-media-server-cve-2026-96656-exploited-chain-patch-and-hunt/cover_hu5450766343746298430.jpg" type="image/jpeg" length="0"/><media:content url="https://firewallsync.com/posts/plex-media-server-cve-2026-96656-exploited-chain-patch-and-hunt/cover_hu5450766343746298430.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><content:encoded><![CDATA[<p><img src="https://firewallsync.com/posts/plex-media-server-cve-2026-96656-exploited-chain-patch-and-hunt/cover_hu5450766343746298430.jpg" alt="A strip of red film curling across a pale surface toward a dark film reel standing on its edge" width="1200" height="630"></p><p>Plex Media Server builds older than 1.43.3.10861 contain four vulnerabilities that the US Cybersecurity and Infrastructure Security Agency (CISA) added to its Known Exploited Vulnerabilities (KEV) catalog on October 20, 2026. Plex says that, chained together, they let an unauthenticated remote attacker run code on the server, and that exploitation is now wide. The fix has been available since September. If you run Plex anywhere, at home, in a lab or on a company network, update it, then check whether it was compromised before you updated.</p>
<p><strong>Scope.</strong> We read the four CVE records in the CVE List, CISA&rsquo;s machine-readable advisory VA-26-266-01, the KEV catalog (version 2026.10.21) and Plex&rsquo;s security thread on its forums, including the October 19, 2026 update, on October 22, 2026. We did not test the vulnerabilities or the proof of concept. For how KEV deadlines work, see <a href="/posts/cisa-bod-26-04-explained-kev-deadlines-forensic-triage-and-what-private-teams-can-borrow/">our explainer on BOD 26-04</a>.</p>
<h2 id="what-is-affected-and-what-fixes-it">What is affected and what fixes it</h2>
<p>Every one of the four CVE records lists Plex Media Server before 1.43.3.10861 as affected and 1.43.3.10861 as unaffected. CISA, acting as the CVE Numbering Authority, published the records and the advisory on September 23, 2026.</p>
<table>
  <thead>
      <tr>
          <th>CVE</th>
          <th>Weakness</th>
          <th>What the record says</th>
          <th>CVSS v3.1 / v4.0 (CVE record)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CVE-2026-96652</td>
          <td>SSRF (CWE-918)</td>
          <td>Any <code>X-Plex-Token</code> value lets an attacker put a full URL in the <code>protocol</code> parameter of <code>/player/timeline</code> and make the server POST to a destination of their choice</td>
          <td>4.3 / 5.3</td>
      </tr>
      <tr>
          <td>CVE-2026-96654</td>
          <td>URL injection (CWE-84)</td>
          <td>URL values in <code>searchOne</code> are not neutralized, so an attacker can call other plugins&rsquo; functions with their own parameters</td>
          <td>6.5 / 6.9</td>
      </tr>
      <tr>
          <td>CVE-2026-96655</td>
          <td>SSRF (CWE-918)</td>
          <td>An authenticated user can make the server request arbitrary internal or external addresses through the <code>/video/:/transcode/universal</code> path parameter</td>
          <td>4.3 / 5.3</td>
      </tr>
      <tr>
          <td>CVE-2026-96656</td>
          <td>File path control (CWE-73)</td>
          <td>An admin user can write files that may be executed on load. The <code>TranscoderH264Options</code> preference is appended verbatim to x264&rsquo;s options on every transcode, and at startup all <code>.so</code> files are loaded without signature, execute-bit or symbol checks</td>
          <td>7.2 / 8.6</td>
      </tr>
  </tbody>
</table>
<p>The individual scores look moderate. That is the trap: each score rates one flaw on its own, while the risk comes from the chain. Plex&rsquo;s update says that chained, the four &ldquo;allow an unauthenticated remote attacker&rdquo; to execute code as the server process. Plex has not published the chain step by step, and we have not reproduced it. Our reading of the CVE descriptions is that the request-forgery and injection flaws provide the access that the file-write flaw, which on its own needs admin rights, requires. Treat that as interpretation, not a confirmed sequence.</p>
<p>The same advisory lists a fifth flaw, CVE-2026-96651, a path traversal in <code>/system/agents/media/get</code> that can read files including the <code>PlexOnlineToken</code>, which the advisory says &ldquo;grants control of the Plex account and server&rdquo;. It is not in KEV, and CISA&rsquo;s enrichment dated September 23 records no exploitation. The same build fixes it.</p>
<h2 id="what-changed-from-routine-update-to-active-exploitation">What changed: from routine update to active exploitation</h2>
<table>
  <thead>
      <tr>
          <th>Date (2026)</th>
          <th>Event</th>
          <th>Source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>September 1</td>
          <td>Plex posts a security notice telling users to update to Plex Media Server 1.43.3 and Plex Desktop 1.115.0</td>
          <td>Plex forum thread</td>
      </tr>
      <tr>
          <td>September 23</td>
          <td>CISA publishes the CVE records and advisory VA-26-266-01, fixed in 1.43.3.10861</td>
          <td>CVE records, CSAF advisory</td>
      </tr>
      <tr>
          <td>October 16</td>
          <td>A public proof of concept is released, according to Plex</td>
          <td>Plex forum update</td>
      </tr>
      <tr>
          <td>October 19</td>
          <td>Plex updates its notice: the flaws are &ldquo;being actively and widely exploited&rdquo;, attackers are installing cryptocurrency miners and proxy software, and unpatched internet-facing servers should be assumed compromised</td>
          <td>Plex forum update</td>
      </tr>
      <tr>
          <td>October 20</td>
          <td>CISA adds the four CVEs to KEV; its enrichment marks exploitation as active for all four</td>
          <td>KEV catalog, CVE records</td>
      </tr>
  </tbody>
</table>
<h3 id="kev-details">KEV details</h3>
<table>
  <thead>
      <tr>
          <th>CVE</th>
          <th>Added</th>
          <th>Due date (federal agencies)</th>
          <th>Forensic triage</th>
          <th>CISA SSVC: Automatable / Technical impact</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CVE-2026-96652</td>
          <td>Oct 20</td>
          <td>Nov 3</td>
          <td>No</td>
          <td>No / Partial</td>
      </tr>
      <tr>
          <td>CVE-2026-96654</td>
          <td>Oct 20</td>
          <td>Oct 23</td>
          <td>No</td>
          <td>Yes / Partial</td>
      </tr>
      <tr>
          <td>CVE-2026-96655</td>
          <td>Oct 20</td>
          <td>Nov 3</td>
          <td>No</td>
          <td>No / Partial</td>
      </tr>
      <tr>
          <td>CVE-2026-96656</td>
          <td>Oct 20</td>
          <td>Oct 23</td>
          <td>Yes</td>
          <td>No / Total</td>
      </tr>
  </tbody>
</table>
<p>Each KEV entry says the flaw can be chained with the other three. The deadlines bind US federal civilian agencies under BOD 26-04; for everyone else they are a signal of urgency. CISA&rsquo;s catalog does not explain why two flaws got three days and two got fourteen.</p>
<h2 id="what-to-do-now">What to do now</h2>
<h3 id="1-update-and-confirm-the-build-number">1. Update and confirm the build number</h3>
<p>Update Plex Media Server to 1.43.3.10861 or later, then confirm the version under <strong>Settings → General</strong> in Plex Web, as Plex&rsquo;s notice describes. &ldquo;1.43.3&rdquo; alone is not enough to be sure: Plex&rsquo;s later update gives the full build number as the threshold. Plex also tells desktop users to update Plex Desktop.</p>
<h3 id="2-decide-whether-the-server-was-exposed">2. Decide whether the server was exposed</h3>
<p>Plex&rsquo;s guidance is that a server running an older build that was reachable from the internet &ldquo;may be compromised&rdquo;. Exposure usually came from Plex&rsquo;s Remote Access feature or a port forward. Plex specifically advises against forwarding port 32400 directly and suggests turning remote access off if you don&rsquo;t need it.</p>
<h3 id="3-look-for-the-signs-plex-lists">3. Look for the signs Plex lists</h3>
<p>Plex&rsquo;s October 19 update names these indicators:</p>
<ul>
<li>Processes you don&rsquo;t recognize running as the Plex user.</li>
<li>Unfamiliar <code>.so</code> (Linux) or <code>.dll</code> (Windows) files in the Plex <strong>Codecs</strong> folder.</li>
<li>Outbound connections to <code>proxystream.st</code>.</li>
<li>High CPU use while nothing is playing.</li>
<li>Transcoder options you did not set in <code>Preferences.xml</code>, which ties directly to CVE-2026-96656&rsquo;s <code>TranscoderH264Options</code> behavior.</li>
</ul>
<p>The location of the Codecs folder and <code>Preferences.xml</code> depends on your operating system and install method; Plex&rsquo;s support documentation lists them. A clean result is not proof of a clean server: these are the indicators Plex has published so far, and an attacker can remove files.</p>
<h3 id="4-if-you-find-something-or-cant-rule-it-out">4. If you find something, or can&rsquo;t rule it out</h3>
<p>Plex&rsquo;s update recommends rebuilding from a clean installation, clearing the Codecs folder and reviewing <code>Preferences.xml</code>. It also says to sign out of all devices and change the Plex account password, and to treat any network shares or credentials the Plex service account could reach as potentially exposed. Because CVE-2026-96651 can expose the server token, signing out all devices after updating is sensible even without other signs; Plex&rsquo;s notice does not explicitly address token rotation.</p>
<h3 id="for-companies">For companies</h3>
<p>If Plex appears in an asset inventory or scanner export, check for it on employee-run lab machines and NAS devices too. Media servers often run under accounts with broad read access to shared storage, which is what turns a hobby service into a foothold. Our guide to <a href="/posts/cisa-kev-json-feed-what-each-field-means-and-how-to-match-it-against-a-scanner-export/">matching the KEV feed against a scanner export</a> shows how to flag entries like these automatically. If you are new to SSRF, <a href="/posts/ssrf-explained-how-server-side-request-forgery-works-and-how-to-prevent-it/">our SSRF explainer</a> covers why &ldquo;make the server send a request&rdquo; is so often the first link in a chain.</p>
<h2 id="limits-of-this-article">Limits of this article</h2>
<p>We did not run the proof of concept or confirm the chain&rsquo;s steps. Plex&rsquo;s statements about exploitation, the proof-of-concept date and the indicators come from its forum post and are not independently verified. We did not read the researcher&rsquo;s write-up referenced in the CVE records. KEV entries and Plex&rsquo;s guidance may change; check the sources below for updates.</p>
<h2 id="sources-and-verification">Sources and verification</h2>
<p>Checked on October 22, 2026.</p>
<table>
  <thead>
      <tr>
          <th>Important claim</th>
          <th>Source</th>
          <th>Verification</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Affected versions (before 1.43.3.10861), descriptions, CWE and CVSS scores of the four CVEs; published September 23, 2026 by CISA as CNA</td>
          <td>CVE records <a href="https://www.cve.org/CVERecord?id=CVE-2026-96652">CVE-2026-96652</a>, <a href="https://www.cve.org/CVERecord?id=CVE-2026-96654">-96654</a>, <a href="https://www.cve.org/CVERecord?id=CVE-2026-96655">-96655</a>, <a href="https://www.cve.org/CVERecord?id=CVE-2026-96656">-96656</a> (CVE List, read via the cvelistV5 repository)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>Advisory VA-26-266-01: risk evaluation, fix in 1.43.3.10861, CVE-2026-96651 details</td>
          <td><a href="https://raw.githubusercontent.com/cisagov/CSAF/develop/csaf_files/IT/white/2026/va-26-266-01.json">CISA CSAF advisory VA-26-266-01</a></td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>KEV additions on October 20, due dates, forensic triage flags, chaining note</td>
          <td><a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog">CISA KEV catalog</a>, version 2026.10.21 (JSON via cisagov/kev-data)</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>CISA SSVC values (exploitation active; automatable; technical impact)</td>
          <td>CISA-ADP containers in the CVE records</td>
          <td>Verified</td>
      </tr>
      <tr>
          <td>September 1 notice; October 19 update on wide exploitation, public proof of concept on October 16, indicators and remediation steps</td>
          <td><a href="https://forums.plex.tv/t/942319">Plex forum: Important Security Update for Plex Media Server v1.43.2 and earlier</a></td>
          <td>Qualified: vendor statements, not independently verified</td>
      </tr>
      <tr>
          <td>The chain&rsquo;s step-by-step mechanics</td>
          <td>Our reading of the CVE descriptions</td>
          <td>Qualified: not confirmed by Plex or reproduced</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item></channel></rss>