<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://adzoic.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://adzoic.github.io/" rel="alternate" type="text/html" /><updated>2026-10-23T12:11:51+00:00</updated><id>https://adzoic.github.io/feed.xml</id><title type="html">AdZoic</title><subtitle>Open-source security tooling and write-ups from the AdZoic team.</subtitle><author><name>AdZoic Team</name></author><entry><title type="html">PHP2Shell: find every vulnerable PHP install in one command</title><link href="https://adzoic.github.io/blog/2026/10/php2shell-check/" rel="alternate" type="text/html" title="PHP2Shell: find every vulnerable PHP install in one command" /><published>2026-10-23T00:00:00+00:00</published><updated>2026-10-23T00:00:00+00:00</updated><id>https://adzoic.github.io/blog/2026/10/php2shell-check</id><content type="html" xml:base="https://adzoic.github.io/blog/2026/10/php2shell-check/"><![CDATA[<p><img src="/assets/img/demo.svg" alt="Animated demo of php2shell-check scanning a Linux host" /></p>

<p><strong>PHP2Shell</strong> (CVE-2026-109618 and CVE-2026-109619) is a pair of critical, unauthenticated remote code execution flaws in PHP. They are triggered while PHP parses <code class="language-plaintext highlighter-rouge">multipart/form-data</code>, before a single line of your application runs. Your framework, your WAF rules in the app, your input validation: none of it gets a say.</p>

<p>It affects PHP-FPM, mod_php, php-cgi, FrankenPHP and LiteSpeed, back to at least PHP 5. The fixes shipped in <strong>8.5.12, 8.4.27, 8.3.36 and 8.2.35</strong>. Anything older is end-of-life and will not get an upstream fix.</p>

<p>The advice is simple: patch. The hard part is knowing <em>what</em> to patch.</p>

<h2 id="why-just-check-the-version-is-not-enough">Why “just check the version” is not enough</h2>

<p>On a real fleet, <code class="language-plaintext highlighter-rouge">php -v</code> on one box tells you very little:</p>

<ul>
  <li><strong>There is rarely one PHP.</strong> A cPanel or Plesk server can have six. Add Remi, SCL, Homebrew, Docker images and a forgotten <code class="language-plaintext highlighter-rouge">/opt/php74</code>, and nobody has the full list.</li>
  <li><strong>Distro back-ports lie to version scanners.</strong> Ubuntu and RHEL patch the CVE but keep the old number. <code class="language-plaintext highlighter-rouge">8.3.6-0ubuntu0.24.04.13</code> is safe; a version-only scanner calls it vulnerable and teaches your team to ignore alerts.</li>
  <li><strong>Patched on disk is not patched in memory.</strong> After <code class="language-plaintext highlighter-rouge">apt upgrade</code>, PHP-FPM workers keep running the old binary until they are restarted. This is the most common post-patch mistake.</li>
  <li><strong>Mitigations are per pool.</strong> The interim setting <code class="language-plaintext highlighter-rouge">session.upload_progress.enabled=0</code> only helps if it is in effect in <em>every</em> FPM pool.</li>
</ul>

<h2 id="what-php2shell-check-does">What php2shell-check does</h2>

<p><a href="https://github.com/AdZoic/php2shell-check">php2shell-check</a> is a single static Go binary with no dependencies, for Linux, macOS, Windows and FreeBSD on amd64 and arm64. Run it and it:</p>

<ol>
  <li><strong>Finds every PHP runtime</strong>: <code class="language-plaintext highlighter-rouge">$PATH</code>, distro packages, Docker official images, Remi, SCL, cPanel EA-PHP, Plesk, CloudLinux, LiteSpeed, Homebrew, MAMP, Herd, XAMPP, Laragon, Scoop and more.</li>
  <li><strong>Checks vendor back-ports</strong> by reading the dpkg or rpm changelog, so patched distro builds show as <code class="language-plaintext highlighter-rouge">PATCHED_BACKPORT</code> instead of a false alarm.</li>
  <li><strong>Finds stale workers</strong> on Linux: php-fpm or <code class="language-plaintext highlighter-rouge">libphp.so</code> processes still running a replaced or deleted binary.</li>
  <li><strong>Checks FPM pool mitigations</strong> across every pool, including <code class="language-plaintext highlighter-rouge">php_admin_value</code> overrides.</li>
  <li><strong>Fails closed.</strong> Anything it cannot prove is patched is reported as needing attention, never as safe.</li>
</ol>

<table>
  <thead>
    <tr>
      <th>Verdict</th>
      <th>Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">PATCHED</code></td>
      <td>At or above the fixed release</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">PATCHED_BACKPORT</code></td>
      <td>Older number, but the vendor changelog lists both CVEs</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">VULNERABLE</code></td>
      <td>Below the fixed release, no back-port evidence</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">VULNERABLE_EOL</code></td>
      <td>Branch older than 8.2: no fix will ever ship</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">UNVERIFIED</code></td>
      <td>Vendor build whose changelog could not be read</td>
    </tr>
  </tbody>
</table>

<h2 id="try-it">Try it</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Linux</span>
curl <span class="nt">-fsSLO</span> https://github.com/AdZoic/php2shell-check/releases/latest/download/php2shell-check_linux_amd64
<span class="nb">chmod</span> +x php2shell-check_linux_amd64
<span class="nb">sudo</span> ./php2shell-check_linux_amd64

<span class="c"># Container images, from any OS with Docker or Podman</span>
php2shell-check image php:8.3-fpm my-registry/app:prod
</code></pre></div></div>

<p>Exit codes are <code class="language-plaintext highlighter-rouge">0</code> safe, <code class="language-plaintext highlighter-rouge">1</code> vulnerable, <code class="language-plaintext highlighter-rouge">2</code> needs attention and <code class="language-plaintext highlighter-rouge">3</code> scan error, so it can gate a CI pipeline directly. There is also a GitHub Action:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">AdZoic/php2shell-check@v1</span>
  <span class="na">with</span><span class="pi">:</span>
    <span class="na">images</span><span class="pi">:</span> <span class="s">my-registry/app:${{ github.sha " }}</span>
</code></pre></div></div>

<h2 id="safe-by-design">Safe by design</h2>

<p>php2shell-check is a defensive tool. It only runs <code class="language-plaintext highlighter-rouge">php -v</code>, <code class="language-plaintext highlighter-rouge">php -i</code> and package-manager queries. It never executes PHP code, never sends requests to your servers and contains <strong>no exploit code</strong>. Image scans run in a throwaway container with no network, all capabilities dropped and a read-only filesystem, and the container is always removed afterwards.</p>

<h2 id="what-to-do-today">What to do today</h2>

<ol>
  <li>Run php2shell-check on every server and in CI against every image you ship.</li>
  <li>Upgrade anything <code class="language-plaintext highlighter-rouge">VULNERABLE</code> to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or later, or install your vendor’s patched package.</li>
  <li><strong>Restart PHP-FPM and your web server</strong>, then run the scan again to confirm no stale workers remain.</li>
  <li>Plan a migration off anything <code class="language-plaintext highlighter-rouge">VULNERABLE_EOL</code>. Interim settings reduce risk; only upgrading removes it.</li>
</ol>

<p>The code is MIT-licensed on <a href="https://github.com/AdZoic/php2shell-check">GitHub</a>. Issues and pull requests are welcome, especially for PHP install locations we do not detect yet.</p>]]></content><author><name>AdZoic Team</name></author><category term="PHP" /><category term="CVE-2026-109618" /><category term="CVE-2026-109619" /><category term="Open source" /><summary type="html"><![CDATA[We built php2shell-check, a free single-binary scanner that finds every PHP runtime on a server or container image, tells you if it is exposed to PHP2Shell, and what to do next.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://adzoic.github.io/assets/img/php2shell-card.png" /><media:content medium="image" url="https://adzoic.github.io/assets/img/php2shell-card.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>