<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Norminal Solutions]]></title><description><![CDATA[Norminal Solutions]]></description><link>https://norminal.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ada97545090efe513e7942a/84ad105c-2bc1-4590-a618-f3dd8979c375.png</url><title>Norminal Solutions</title><link>https://norminal.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 29 Oct 2026 18:27:45 GMT</lastBuildDate><atom:link href="https://norminal.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A careful AI agent prompt for PHP2Shell]]></title><description><![CDATA[A read-first prompt for Claude Code, Codex or other agents: find every PHP runtime, check the real package build, wait for approval before changes]]></description><link>https://norminal.hashnode.dev/a-careful-ai-agent-prompt-for-php2shell</link><guid isPermaLink="true">https://norminal.hashnode.dev/a-careful-ai-agent-prompt-for-php2shell</guid><category><![CDATA[PHP]]></category><category><![CDATA[Security]]></category><category><![CDATA[AI]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Norminal Solutions]]></dc:creator><pubDate>Tue, 27 Oct 2026 16:40:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ada97545090efe513e7942a/0083a3cc-75e4-49aa-92d4-dcf85a25a0af.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Coding and operations agents can do most of the PHP2Shell work (CVE-2026-109618 and CVE-2026-109619): find every PHP runtime, read the versions, and prepare the update. They can also do damage if they restart the wrong service or trust the wrong version number.</p>
<p>The PHP Foundation describes its own use of AI for this release like this: "AI helps the team validate reports and group reports sharing the same root cause, but a person makes every call and works on every patch" (<a href="https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/">PHP Foundation, 21 October 2026</a>). The same rule works on your servers: let the agent read and propose, and keep the changes for yourself to approve.</p>
<p>Disclosure: we run <a href="https://php2shell.fyi/?ref=hashnode">php2shell.fyi</a>, a passive checker for PHP2Shell.</p>
<h2>The prompt</h2>
<p>Replace <code>https://your-site.example/</code> with your own site. Give the agent access only to systems you own or run.</p>
<pre><code class="language-text">You have access to the server or repository behind https://your-site.example/. Check it for PHP2Shell (CVE-2026-109618 and CVE-2026-109619) and help me fix it.

1. Inventory every PHP runtime: CLI, PHP-FPM pools, Apache mod_php, php-cgi, LiteSpeed lsphp, FrankenPHP, cPanel/Plesk/Remi builds under /opt, containers and images, CI jobs. In a repository, read Dockerfiles, compose files, CI configs and composer.json (require.php, config.platform.php).
2. For each one, record the version (php -v, php-fpmX.Y -v) and the package build (dpkg -l, rpm -qa or apk info -v, filtered to php).
3. Compare with the fixed releases: 8.2.35, 8.3.36, 8.4.27 and 8.5.12 or later in the same branch. PHP 8.1 and older get no upstream release. A distribution build can carry the fix under an old number: compare the full package version with the vendor's advisory.
4. Propose the upgrade: exact commands, services to restart, expected downtime. Ask me before you run anything that installs, removes, restarts or edits, and before you create any file in the web root (no phpinfo files).
5. After my approval: take a backup or snapshot, update, restart every PHP worker (and lsphp in LiteSpeed detached mode), rebuild images, then verify the version, the package, that every PHP process started after the update (ps -eo pid,lstart,cmd) and X-Powered-By (curl -sIL).
6. Report a table: runtime, path, version, package, status (fixed, not fixed, unknown) and what is left to do.

Never send exploit probes to any site. Do not paste secrets or environment values (php -i and ps can show them) into your report. If you cannot verify a version, report it as unknown.
</code></pre>
<p>The same steps are also a skill file for agents that load skills, such as Claude Code: <a href="https://php2shell.fyi/skills/php2shell-fix/SKILL.md">SKILL.md</a>. It is text only. Read it before you install it.</p>
<h2>Why each line is there</h2>
<ul>
<li><strong>Step 1 lists runtimes, not sites.</strong> The command-line <code>php</code> is often not the PHP that serves the site. Panels such as cPanel and Plesk install their own PHP builds next to the system ones.</li>
<li><strong>Step 3 names the backport trap.</strong> Ubuntu 24.04 has the fix in <code>8.3.6-0ubuntu0.24.04.13</code> (<a href="https://ubuntu.com/security/notices/USN-8948-1">USN-8948-1</a>), so <code>php -v</code> still says 8.3.6. An agent that compares 8.3.6 with 8.3.36 would "fix" a fixed server.</li>
<li><strong>Step 4 is the approval gate.</strong> The agent stops before any install, restart or edit. It also must not leave a <code>phpinfo()</code> file online: that page shows paths, settings and environment values.</li>
<li><strong>Step 5 checks the restart.</strong> An installed package does not change PHP processes that are already running.</li>
<li><strong>The last lines keep it defensive.</strong> No exploit probes against any site, and no secrets in the report.</li>
</ul>
<h2>Until you can update</h2>
<p>If one runtime cannot be updated yet, the PHP project lists measures that reduce specific attack paths, such as <code>session.upload_progress.enabled=0</code> set in <code>php.ini</code> or the FPM pool, not with <code>ini_set()</code>. On 23 October 2026, <a href="http://php.net">php.net</a> also suggested keeping that setting off until the next regular bugfix release, even on the fixed releases (<a href="https://www.php.net/archive/2026.php#2026-10-23-1">informational advisory</a>, CVE-2026-115560). The full list, with a source for each measure, is on <a href="https://php2shell.fyi/mitigations?ref=hashnode">php2shell.fyi/mitigations</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Why your scanner or AI agent can call a fixed PHP server vulnerable]]></title><description><![CDATA[Ubuntu, RHEL, Chainguard fix PHP2Shell under old version numbers. Tools that compare the upstream number get it wrong. How to check the real build.]]></description><link>https://norminal.hashnode.dev/why-your-scanner-or-ai-agent-can-call-a-fixed-php-server-vulnerable</link><guid isPermaLink="true">https://norminal.hashnode.dev/why-your-scanner-or-ai-agent-can-call-a-fixed-php-server-vulnerable</guid><category><![CDATA[PHP]]></category><category><![CDATA[Security]]></category><category><![CDATA[Linux]]></category><category><![CDATA[AI]]></category><dc:creator><![CDATA[Norminal Solutions]]></dc:creator><pubDate>Fri, 23 Oct 2026 22:48:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ada97545090efe513e7942a/1f7e6a0e-000b-4095-960c-4c1f01ea203f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After the PHP2Shell release (CVE-2026-109618 and CVE-2026-109619, <a href="https://www.php.net/archive/2026.php#2026-10-21-5">php.net advisory of 21 October 2026</a>), many people ran a scanner or asked an AI agent whether their servers are fixed. On some systems, the answer comes back wrong in both directions.</p>
<p>Disclosure: we run <a href="https://php2shell.fyi/?ref=hashnode">php2shell.fyi</a>, a passive checker for PHP2Shell.</p>
<h2>Wrong answer 1: a fixed server shows as vulnerable</h2>
<p>The PHP project fixed the flaws in PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12. Some distributions put the fix into the version they already ship and keep the old upstream number:</p>
<table>
<thead>
<tr>
<th>System</th>
<th>Fixed build</th>
<th><code>php -v</code> shows</th>
</tr>
</thead>
<tbody><tr>
<td>Ubuntu 24.04</td>
<td><code>php8.3</code> <code>8.3.6-0ubuntu0.24.04.13</code> (<a href="https://ubuntu.com/security/notices/USN-8948-1">USN-8948-1</a>)</td>
<td>8.3.6</td>
</tr>
<tr>
<td>Ubuntu 22.04</td>
<td><code>php8.1</code> <code>8.1.2-1ubuntu2.28</code> (USN-8948-1)</td>
<td>8.1.2</td>
</tr>
<tr>
<td>RHEL 9</td>
<td><code>php-8.0.30-8.el9_8.1</code> (<a href="https://access.redhat.com/errata/RHSA-2026:87151">RHSA-2026:87151</a>)</td>
<td>8.0.30</td>
</tr>
<tr>
<td>Chainguard</td>
<td><code>php-8.4</code> <code>8.4.26-r4</code></td>
<td>8.4.26</td>
</tr>
</tbody></table>
<p>A tool that reads only <code>8.3.6</code> and compares it with <code>8.3.36</code> says "vulnerable". The ProjectDiscovery Nuclei template for CVE-2026-109618 does this in its version fallback, and so does the Assetnote scanner when it sees no crash signal. Some community agent skills do the same with <code>sort -V</code>.</p>
<p>Not every distribution does this. Debian, Alpine, the RHEL modules and RHEL 10 ship the new upstream numbers, for example Debian 13 <code>8.4.27-1~deb13u1</code>.</p>
<h2>Wrong answer 2: an old branch shows as not affected</h2>
<p>The CVE record for CVE-2026-109618 lists only the 8.2, 8.3, 8.4 and 8.5 branches as affected, and marks every other version as unaffected (<a href="https://www.cve.org/CVERecord?id=CVE-2026-109618">cve.org</a>, checked 23 October 2026). A scanner that reads the record literally can call PHP 8.1 and older "not affected".</p>
<p>They are affected. The PHP security team published source fixes for 7.4, 8.0 and 8.1, and the researchers found affected releases back to PHP 5.4 (<a href="https://php2shell.com/">php2shell.com</a>).</p>
<h2>How to check the real build</h2>
<p>Read the package version of the PHP that serves the site, not only <code>php -v</code>:</p>
<pre><code class="language-sh"># Debian and Ubuntu
dpkg -l 'php*' | grep '^ii'
# RHEL, AlmaLinux, Rocky
rpm -qa 'php*'
# Alpine and Wolfi
apk info -v | grep '^php'
</code></pre>
<p>Compare the full version with the fixed build in your vendor's notice. On Debian and Ubuntu, <code>dpkg --compare-versions</code> does this correctly; on RPM systems, compare within the same release and stream.</p>
<p>Then check that PHP restarted. An installed package does not change PHP processes that are already running:</p>
<pre><code class="language-sh">ps -eo pid,lstart,cmd | grep -i '[p]hp'
</code></pre>
<p>A PHP-FPM, Apache or LiteSpeed process that started before the update still runs the old code.</p>
<h2>If you use an AI agent</h2>
<p>Tell it which comparison to use. For example: "Compare the full package version with the vendor's fixed build. Do not compare <code>php -v</code> with upstream numbers. If you cannot verify a version, report it as unknown." The agent skills from OpenAI (<code>phpcheck-server</code>), Cognition (<code>fix-php-vuln</code>) and Chainguard already work this way.</p>
<p>The fixed builds for Ubuntu, Debian, RHEL and Alpine, with the vendor links, are on <a href="https://php2shell.fyi/linux?ref=hashnode">php2shell.fyi/linux</a>.</p>
]]></content:encoded></item><item><title><![CDATA[AI agent skills for PHP2Shell: what each one checks]]></title><description><![CDATA[Several agent skills now help find and fix PHP2Shell. They differ in what they inspect, how they compare versions, and when they ask before a change.]]></description><link>https://norminal.hashnode.dev/ai-agent-skills-for-php2shell-what-each-one-checks</link><guid isPermaLink="true">https://norminal.hashnode.dev/ai-agent-skills-for-php2shell-what-each-one-checks</guid><category><![CDATA[PHP]]></category><category><![CDATA[Security]]></category><category><![CDATA[AI]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Norminal Solutions]]></dc:creator><pubDate>Fri, 23 Oct 2026 22:39:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ada97545090efe513e7942a/c182d62e-b3c4-4fd2-9e2b-c2ffe5718852.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PHP2Shell (CVE-2026-109618 and CVE-2026-109619) is a pair of flaws in PHP itself. The PHP project fixed them on 21 October 2026 in PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 (<a href="https://www.php.net/archive/2026.php#2026-10-21-5">php.net advisory</a>).</p>
<p>Within two days, several teams published skills for coding and operations agents (Claude Code, Codex, Devin and others) that look for affected PHP and help update it. We read the skill files of the ones below. This post lists what each one inspects, how it decides whether a build has the fix, and whether it waits for your approval before it changes anything.</p>
<p>Disclosure: we run <a href="https://php2shell.fyi/?ref=hashnode">php2shell.fyi</a>, a passive checker for PHP2Shell. None of the tools below is ours.</p>
<h2>The question that matters most</h2>
<p>Some Linux distributions ship the fix under the old version number. Ubuntu 24.04 has the fix in <code>php8.3</code> <code>8.3.6-0ubuntu0.24.04.13</code> (<a href="https://ubuntu.com/security/notices/USN-8948-1">USN-8948-1</a>). RHEL 9 has it in <code>php-8.0.30-8.el9_8.1</code> (<a href="https://access.redhat.com/errata/RHSA-2026:87151">RHSA-2026:87151</a>). Chainguard has it in <code>8.4.26-r4</code>.</p>
<p>A tool that compares only the upstream number (8.3.6 is lower than 8.3.36) reports these fixed servers as vulnerable. An agent that trusts that answer may try to "fix" a server that is already fixed. So the first column we checked is: does the tool compare the full package version?</p>
<h2>The skills</h2>
<table>
<thead>
<tr>
<th>Skill</th>
<th>Publisher</th>
<th>What it inspects</th>
<th>Full package version?</th>
<th>Changes</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://github.com/openai/php2shell-checker"><code>phpcheck-server</code></a></td>
<td>OpenAI</td>
<td>The PHP binary or Apache module that serves the site, its package, the OS, containers</td>
<td>Yes</td>
<td>Check only</td>
</tr>
<tr>
<td><a href="https://github.com/openai/php2shell-checker"><code>phpcheck-url</code></a></td>
<td>OpenAI</td>
<td>The <code>Server</code> and <code>X-Powered-By</code> headers of one URL</td>
<td>No, and it says so</td>
<td>Check only</td>
</tr>
<tr>
<td><a href="https://github.com/CognitionAI/devin-vuln-fixes"><code>fix-php-vuln</code></a></td>
<td>Cognition</td>
<td>Repositories: Dockerfiles, CI, Helm, Terraform, Ansible, Chef, Puppet</td>
<td>Yes</td>
<td>Only after you pick the repos; then one pull request per repo</td>
</tr>
<tr>
<td><a href="https://github.com/chainguard-dev/cg-skills"><code>php2shell</code></a></td>
<td>Chainguard</td>
<td>Chainguard and Wolfi images, SBOMs, Kubernetes workloads</td>
<td>Yes (apk revisions)</td>
<td>Each change needs approval</td>
</tr>
<tr>
<td><a href="https://github.com/rogulia/skills"><code>php2shell-response</code></a></td>
<td>Iurii Rogulia (community)</td>
<td>Hosts, images, hosting accounts, repositories</td>
<td>Yes</td>
<td>Read-only unless you say otherwise</td>
</tr>
</tbody></table>
<p>What the skill files say, in their own words:</p>
<ul>
<li><strong>OpenAI</strong> <code>phpcheck-server</code><strong>:</strong> "Compare the full package revision against vendor guidance covering both CVEs. An older upstream version alone does not prove vulnerability." It also asks whether the web workers restarted after the update, and says: "Do not run exploit probes."</li>
<li><strong>OpenAI</strong> <code>phpcheck-url</code><strong>:</strong> "HTTP headers cannot tell whether the version contains a backported fix." Use it for a first look, not for a verdict.</li>
<li><strong>Cognition</strong> <code>fix-php-vuln</code><strong>:</strong> "Never compare <code>php -v</code> with upstream numbers to decide this." Discovery ends with: "Stop. Show the table and ask which repos to patch."</li>
<li><strong>Chainguard</strong> <code>php2shell</code><strong>:</strong> "Every change needs the user's explicit approval first". It also warns: "Never compare version strings as text (<code>-r10</code> is newer than <code>-r4</code>)".</li>
<li><code>php2shell-response</code><strong>:</strong> "A distribution package may carry the fix under an older version number: check the vendor changelog or advisory, never compare version strings alone." Its mode: "Read-only unless the user says otherwise."</li>
</ul>
<h2>Tools that compare only the upstream number</h2>
<p>These are useful, but read their "vulnerable" answer as a question, not a verdict, on Ubuntu, RHEL and Chainguard:</p>
<ul>
<li>The ProjectDiscovery <a href="https://github.com/projectdiscovery/nuclei-templates/blob/main/http/cves/2026/CVE-2026-109618.yaml">Nuclei template</a> for CVE-2026-109618. Its version fallback marks a patch number below the fixed one as vulnerable, so <code>8.3.6-0ubuntu0.24.04.13</code> counts as vulnerable. It also marks every version below 8.2 as end of life.</li>
<li>The <a href="https://github.com/assetnote/php2shell-scanner">Assetnote scanner</a>. When it sees no crash signal, it falls back to the <code>X-Powered-By</code> number with the same comparison.</li>
<li>Some community skills compare versions with <code>sort -V</code> on the upstream number only.</li>
</ul>
<h2>Before you let an agent change a server</h2>
<ul>
<li>Give it read access first, and ask for a table: runtime, path, version, package, status.</li>
<li>Check that it reads the PHP that serves the site (PHP-FPM, the Apache module, LiteSpeed), not only <code>php -v</code> on the command line.</li>
<li>Ask it to show the restart step. Old PHP processes keep the old code until they stop. <code>ps -eo pid,lstart,cmd | grep -i '[p]hp'</code> shows when each one started.</li>
<li>Do not let it fetch or run public proof-of-concept code. Most public PHP2Shell "PoC" repositories are attack tools, and their code is not reviewed.</li>
</ul>
<p>We keep a read-first prompt, our own <code>SKILL.md</code> and this comparison up to date on <a href="https://php2shell.fyi/ai-agents?ref=hashnode">php2shell.fyi/ai-agents</a>. The fixed releases, the distribution builds and the mitigations are on <a href="https://php2shell.fyi/fixed-versions?ref=hashnode">php2shell.fyi</a>, with a source for each fact.</p>
]]></content:encoded></item><item><title><![CDATA[Your server says PHP 8.3.6. Is it fixed for PHP2Shell?]]></title><description><![CDATA[Distros keep old PHP version numbers on fixed builds. How to read the package version, compare it with the fixed build, and restart PHP the right way.]]></description><link>https://norminal.hashnode.dev/your-server-says-php-8-3-6-is-it-fixed-for-php2shell</link><guid isPermaLink="true">https://norminal.hashnode.dev/your-server-says-php-8-3-6-is-it-fixed-for-php2shell</guid><category><![CDATA[PHP]]></category><category><![CDATA[Security]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Norminal Solutions]]></dc:creator><pubDate>Thu, 22 Oct 2026 23:39:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ada97545090efe513e7942a/12db244c-0533-42f8-be0d-a02a2f81f775.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You read the PHP2Shell advisory. The fixed releases are PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12. You log in to your Ubuntu 24.04 server, run <code>php -v</code>, and it says <code>PHP 8.3.6</code>. That is thirty patch releases below 8.3.36.</p>
<p>Is the server exposed? Maybe not. This article shows how to get a real answer in about five minutes.</p>
<h2>Why the number can lie</h2>
<p>PHP2Shell (CVE-2026-109618 and CVE-2026-109619, CVSS 9.2) is a pair of flaws in PHP itself, not in WordPress, Laravel or any other app. The PHP project published the fixes on 21 October 2026 (<a href="https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w">GHSA-w8hw-w9fx-j79w</a>, <a href="https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp">GHSA-6wmf-4rv5-p3rp</a>). The research is on <a href="https://php2shell.com/">php2shell.com</a>.</p>
<p>Linux distributions do not jump to a new upstream release in a stable branch. They take the fix, apply it to the version they already ship, and add a build number to the package version. So the upstream number stays the same, and only the package version changes:</p>
<table>
<thead>
<tr>
<th>Distribution</th>
<th>Package</th>
<th>Fixed package version</th>
</tr>
</thead>
<tbody><tr>
<td>Ubuntu 24.04 LTS</td>
<td>php8.3</td>
<td><code>8.3.6-0ubuntu0.24.04.13</code></td>
</tr>
<tr>
<td>Ubuntu 22.04 LTS</td>
<td>php8.1</td>
<td><code>8.1.2-1ubuntu2.28</code></td>
</tr>
<tr>
<td>Ubuntu 26.04 LTS</td>
<td>php8.5</td>
<td><code>8.5.4-0ubuntu1.5</code></td>
</tr>
<tr>
<td>Debian 13 trixie</td>
<td>php8.4</td>
<td><code>8.4.27-1~deb13u1</code></td>
</tr>
<tr>
<td>Debian 12 bookworm</td>
<td>php8.2</td>
<td><code>8.2.35-1~deb12u1</code></td>
</tr>
<tr>
<td>RHEL 9 (default stream)</td>
<td>php</td>
<td><code>8.0.30-8.el9_8.1</code></td>
</tr>
<tr>
<td>RHEL 10</td>
<td>php</td>
<td><code>8.3.36-1.el10_2</code></td>
</tr>
<tr>
<td>Alpine v3.23 and newer</td>
<td>php83</td>
<td><code>8.3.36-r0</code></td>
</tr>
</tbody></table>
<p>These are the versions published by each vendor as of 22 October 2026. Vendors add and change entries, so confirm on your vendor's security tracker before you decide.</p>
<p>The important part: <code>php -v</code> and the <code>X-Powered-By</code> header both show only <code>8.3.6</code>. Neither shows the <code>-0ubuntu0.24.04.13</code> part. To know, you have to read the package.</p>
<h2>Step 1: find the PHP that serves your site</h2>
<p><code>php -v</code> answers for the command-line PHP. Your site runs on PHP-FPM, Apache <code>mod_php</code> or <code>php-cgi</code>, and that can be a different install. Find the one that serves requests first.</p>
<pre><code class="language-bash"># PHP-FPM services that are running
systemctl list-units --type=service 'php*'

# Apache with mod_php?
apachectl -M 2&gt;/dev/null | grep -i php
</code></pre>
<p>On Debian and Ubuntu, each branch has its own FPM binary:</p>
<pre><code class="language-bash">php-fpm8.3 -v
</code></pre>
<p>On RHEL, AlmaLinux and Rocky it is <code>php-fpm -v</code>. If you are still not sure, put a <code>phpinfo()</code> page on the site, read the <strong>Server API</strong> line, and delete the page right after.</p>
<p>More than one branch on the box is common, for example 8.1 for an old site and 8.3 for the rest. Every branch that serves a site counts.</p>
<h2>Step 2: read the package version</h2>
<p>Debian and Ubuntu:</p>
<pre><code class="language-bash">dpkg-query -W -f='${Package} ${Version}\n' 'php*-fpm' 'php*-common' 'libapache2-mod-php*' 2&gt;/dev/null
</code></pre>
<p>RHEL, AlmaLinux and Rocky:</p>
<pre><code class="language-bash">rpm -q php-common php-fpm
dnf module list php   # the enabled stream is marked [e]
</code></pre>
<p>Alpine:</p>
<pre><code class="language-bash">apk info -v | grep '^php'
</code></pre>
<h2>Step 3: compare it with the fixed build</h2>
<p>Do not compare by eye. Let the package manager do it. On Debian and Ubuntu:</p>
<pre><code class="language-bash">installed=$(dpkg-query -W -f='${Version}' php8.3-fpm)
dpkg --compare-versions "$installed" ge "8.3.6-0ubuntu0.24.04.13" \
  &amp;&amp; echo "at or above the fixed build" \
  || echo "older than the fixed build: update"
</code></pre>
<p>Put your own package name and your release's fixed version in the command. On RPM systems, <code>rpmdev-vercmp</code> (from <code>rpmdevtools</code>) does the same job.</p>
<p>Two traps:</p>
<ul>
<li><strong>AlmaLinux and Rocky have their own build strings.</strong> AlmaLinux builds end in <code>.alma.1</code>, and Rocky module builds have their own suffix. Compare with your distribution's string, not with Red Hat's.</li>
<li><strong>Ubuntu 20.04 and older</strong> get the fix through Ubuntu Pro (ESM). Without Pro, <code>apt upgrade</code> does not install it.</li>
</ul>
<h2>Step 4: update, then restart</h2>
<p>If the package is older than the fixed build, update it:</p>
<pre><code class="language-bash"># Debian / Ubuntu
sudo apt update &amp;&amp; sudo apt upgrade

# RHEL / AlmaLinux / Rocky
sudo dnf upgrade 'php*'

# Alpine
apk update &amp;&amp; apk upgrade
</code></pre>
<p>Then restart. This is the step people forget. Running PHP processes keep the old code in memory until they stop, so a new package on disk changes nothing yet.</p>
<pre><code class="language-bash">sudo systemctl restart php8.3-fpm   # use your branch
sudo systemctl restart apache2      # or httpd on RHEL
</code></pre>
<p>Restart queue workers, Laravel Octane, Symfony Messenger consumers and any other long-running PHP process too. Then repeat Step 1 and Step 2 to confirm what is running now.</p>
<h2>Containers</h2>
<p><code>docker restart</code> keeps the old PHP, because the PHP is in the image. Pull the updated base image, rebuild your image and recreate the container. Official <code>php</code> images use upstream releases, so look for 8.2.35, 8.3.36, 8.4.27 or 8.5.12 there. Images built on a distribution's own PHP packages follow the distribution table above.</p>
<h2>PHP 7.4, 8.0 and 8.1</h2>
<p>The PHP project ships no new release for these branches. Its security team published source patches for 7.4, 8.0 and 8.1, for people who build PHP themselves. Everyone else needs a fixed build from a distribution, host or LTS vendor (for example Ubuntu 22.04's <code>8.1.2-1ubuntu2.28</code>, or RHEL 8's php:7.4 stream), or a move to 8.2 or newer. Note that 8.2 itself reaches end of life on 31 December 2026.</p>
<h2>What the outside view can and cannot tell</h2>
<p>From outside, the only version hint is the <code>X-Powered-By</code> header, which PHP adds when <code>expose_php</code> is on:</p>
<pre><code class="language-plaintext">X-Powered-By: PHP/8.3.6
</code></pre>
<p>That one line is useful. <code>PHP/8.3.12</code> on branch 8.3 is clearly below 8.3.36, and no distribution ships that number as a fixed build. But <code>PHP/8.3.6</code> can be either the old Ubuntu build or the fixed one, because the header never shows the package suffix. And a missing header tells you nothing at all. Hiding it with <code>expose_php = Off</code> is fine hardening, and it does not fix PHP2Shell.</p>
<p>A header is a hint, not proof. Use it as a quick first look at your own sites, then confirm on the server with the steps above. Our team built a free checker that reads the header and knows these distribution builds. It answers "not fixed", "fixed release", "check the package" or "cannot tell": <a href="https://php2shell.fyi/?ref=hashnode">php2shell.fyi</a>.</p>
<h2>Checklist</h2>
<ol>
<li>Find every PHP that serves a site (FPM pools, <code>mod_php</code>, containers).</li>
<li>Read the full package version, not <code>php -v</code>.</li>
<li>Compare it with your vendor's fixed build using the package manager.</li>
<li>Update, then restart PHP-FPM, Apache and long-running workers.</li>
<li>On 7.4, 8.0 or 8.1, get a vendor build or plan the move.</li>
<li>After the update, rotate the secrets PHP could read on hosts that ran an affected version. The flaws can leak server memory.</li>
</ol>
<hr />
<p><em>This article was drafted with AI assistance and checked by the php2shell.fyi team. php2shell.fyi is unofficial and not affiliated with PHP or</em> <a href="http://php2shell.com"><em>php2shell.com</em></a><em>. Package versions are as published by each vendor on 22 October 2026.</em></p>
]]></content:encoded></item></channel></rss>