What the BSI reports on PHP2Shell
The BSI security advisory "PHP: Kritische Schwachstellen bedrohen Webanwendungen weltweit" (critical vulnerabilities threaten web applications worldwide) carries the number BITS-H 2026-297981-1232 and is available in version 1.2 of October 22, 2026 (BSI). It covers two vulnerabilities, CVE-2026-109618 and CVE-2026-109619, each rated 9.2 out of 10 under CVSS version 4.0 (BSI). According to the information given there, all known PHP versions are affected, going back to at least PHP 5 (BSI). The name PHP2Shell comes from media coverage and is meant to show the similarity to the earlier Log4Shell vulnerability (BSI).
The vulnerabilities are fixed in versions 8.5.12, 8.4.27, 8.3.36 and 8.2.35 (PHP Group). For branches 8.1 and older, the PHP project no longer ships updates (PHP Group); for the end-of-life versions 7.4, 8.0 and 8.1, the PHP security team only provided backport patches for the source code (BSI). One sentence in the advisory matters most for the inventory: the vulnerabilities affect the PHP runtime itself, not specific applications (BSI). An update of WordPress, Shopware or TYPO3 therefore does not close them; the runtime underneath has to be updated as well.
In the BSI scheme, level orange means that measures must be taken without delay (BSI). That is a clear statement, but not a reason for rushing without a plan. Whoever has a complete list first patches in a sensible order and can show afterwards what happened when.
Why PHP2Shell is an inventory question first
For a vulnerability in a plugin, a look at the plugin list is often enough. For a vulnerability in the runtime, the question is broader: every website whose pages are served by PHP is a candidate, regardless of the CMS. The joint statement by the European Commission, ENISA, CERT-EU, Europol and the network of national CSIRTs frames the first step accordingly: organizations should identify their PHP-based applications, coordinate with hosting and service providers and apply the updates (ENISA). Systems reachable from the internet should come first (ENISA).
Agencies face a second layer: responsibility. For a website on its own server, the agency patches it itself; on shared hosting or a managed server, the host does; in a container deployment, whoever builds the image. The BSI points out specifically that applications in Docker containers must be updated or rebuilt independently of the host if they use PHP (BSI). A list that only contains domains does not answer the question "Who does what?"
PHP also sits behind more than classic websites: many products rely on PHP in the background and may be affected even if they do not look like it (ENISA). This article stays with websites; devices with a web interface belong on a separate list. For each website, the list should carry at least these fields:
- Address and environment: live, staging, microsite, landing page. Every environment with its own PHP instance counts separately.
- Hosting: own server, managed server, shared hosting or container, plus the contact person at the host.
- PHP branch and package level: as
php -vand the package manager show it, not only as the header claims it. - Server API: PHP-FPM, Apache with mod_php, php-cgi or another server. The PHP project considers the risk highest for mod_php (PHP Group).
- Responsible for the patch: agency, host or client, by name.
- Record: date of the update, date of the restart, result of the check.
Step 1: Capture all websites, not just the familiar ones
The list does not start in monitoring but in contracts, in DNS and in hosting accounts. Typical gaps in the inventory are staging environments, pages from past campaigns, an old customer portal and websites that keep running under a second address after a relaunch. In our experience, this is exactly where the oldest PHP branches live.
If a website is in monitoring, the CRA component cockpit provides an account-wide overview: per website, the number of detected components, the number of potentially outdated components, the number of components with a readable version, the highest severity and the time of the last tech stack check. The list is sorted by the number of potentially outdated components, so the most conspicuous websites appear at the top. It covers your own websites and those shared with the account, which brings the inventory together in one place for agencies with team and client access. The cockpit is included from the Business plan upward.
Whatever is not in monitoring is missing there as well. Comparing the list from contracts and DNS with the list in the cockpit is therefore the first real finding of the inventory: every domain that shows up on only one of the two sides is an open question. Adding the missing websites to monitoring while you are at it gives you a more complete starting point the next time.
The name of the cockpit refers to the Cyber Resilience Act, under which manufacturers of products with digital elements have had to report actively exploited vulnerabilities since September 11, 2026 (ENISA). Operators who only run websites are generally not covered; the component list is useful regardless.
Step 2: Detect PHP as far as it is visible from the outside
From the outside, PHP mainly reveals itself through the X-Powered-By header. The expose_php setting announces there that PHP is installed on the server, including the version number (PHP manual). Some servers also name PHP in the Server header. XICTRAQ reads both headers during the scan and derives the PHP component in the cockpit from them. The security scan also lists a visible X-Powered-By header as a finding, because it gives attackers the same information it gives monitoring.
How much of this is visible on the web is measured by the Web Almanac, based on the hosts crawled by the HTTP Archive: the X-Powered-By header appears on 23.9 percent of these hosts (Web Almanac 2025), and more than 27 percent of these headers contain version information (Web Almanac 2025). According to the same analysis, PHP tends to expose the exact version particularly in X-Powered-By (Web Almanac 2025). Conversely, this means that for a large share of websites no PHP version is visible from the outside at all.
Where the header stays silent, the system behind it helps. WordPress, Drupal, TYPO3, Joomla and Magento were developed in PHP (BSI), so a website running one of these systems is a PHP candidate even if no version is visible. A session cookie with the default name PHPSESSID is another indicator. The cockpit then lists a detected CMS as a component, but no PHP version. Its key figures show how many components reveal a version at all; if not a single one does, it displays "not assessable" instead of a reassuring zero.
The article on turning off version banners recommends removing the version number from the headers. PHP2Shell does not change that. The inventory does not need the number from the outside but from the inside: for every website with a hidden version, the operator enters the level from php -v and the package manager into the list. The outside view then only checks whether the header stays hidden.
Step 3: Prioritize by end of life
Not every website is equally urgent. The longest path to a fix belongs to branches for which the PHP project no longer ships updates. The BSI notes that all PHP versions before 8.2 have already reached end of life (BSI) and that PHP 8.2 receives security updates only until the end of the year (BSI). The PHP project's table gives December 31, 2026 for this (PHP Group). Under the project's rule, each branch receives two years of active support and then two more years of fixes for critical security issues only (PHP Group).
| PHP branch | Security updates until | Version with PHP2Shell patch | Priority in the list |
|---|---|---|---|
| 5.x to 7.3 | ended years ago | only via long-term support vendors | first, plan the upgrade |
| 7.4 and 8.0 | ended Nov 28, 2022 and Nov 26, 2023 | source backport or distribution package | first, plan the upgrade |
| 8.1 | ended Dec 31, 2025 | source backport or distribution package | first, plan the upgrade |
| 8.2 | Dec 31, 2026 | 8.2.35 | high, plan the move as well |
| 8.3 | Dec 31, 2027 | 8.3.36 | check patch level |
| 8.4 | Dec 31, 2028 | 8.4.27 | check patch level |
| 8.5 | Dec 31, 2029 | 8.5.12 | check patch level |
| unknown | unknown | unknown | clarify from the inside before the supported branches |
The table data comes from the overviews of supported and unsupported branches (PHP Group) and from the security advisory of October 21, 2026 (PHP Group). Websites on branches without security updates come first, because the PHP project has no finished version with the patch for them. The BSI names exactly these systems, alongside those still unpatched, as the reason the number of vulnerable systems worldwide remains high (BSI). Next come websites with a hidden version, because nothing is known about them, and only then the supported branches, where only the patch level needs checking.
For 8.2, it makes sense to combine the patch with a move to a newer branch. How the upgrade works for WordPress is described in the article on the end of support for PHP 8.2, and planning safe upgrades for a store in the article on PHP end-of-life management. The cockpit takes over part of the sorting: it marks a visible PHP version below 8.2 as end of life, with a severity that depends on the age of the branch, and such websites move up in the overview. How to track end-of-life dates across the whole web stack, not just for PHP, is covered in the article on end of life in the web stack.
What the heuristic assesses and what it does not
This is the most important limitation of the process, and it should be stated openly. XICTRAQ only sees what the server shows from the outside. The assessment in the cockpit is an offline heuristic: it compares the visible version number with stored thresholds without querying a vulnerability database live. The PHP2Shell identifiers CVE-2026-109618 and CVE-2026-109619 are not part of these rules. XICTRAQ does not detect PHP2Shell and does not pretend to.
For PHP, the heuristic draws the line at end of life: below 8.2 it reports a finding, from 8.2 on it does not. It does not assess the patch level within branches 8.2 to 8.5. A website that reports PHP/8.3.20 is therefore not considered outdated there, even though 8.3.20 is below the fixed version 8.3.36 (PHP Group). For these websites, the inventory supplies the list; checking the patch level remains the operator's job.
The second limit is the backport. Linux distributions often apply security fixes to their packages without raising the version number to the PHP project's level. The BSI writes that comparing the installed version with the patched version provided by the distribution may be necessary (BSI). How differently this looks is shown by the distributions' security pages for CVE-2026-109618:
- Debian 12 ships the fix in package
8.2.35-1~deb12u1, i.e. with the PHP project's fixed version number (Debian). - Ubuntu 24.04 LTS ships it in package
8.3.6-0ubuntu0.24.04.13(Ubuntu). The base version 8.3.6 is far below 8.3.36, yet the package is fixed. - Ubuntu 22.04 LTS even fixes branch 8.1, which no longer receives updates from the PHP project, in package
8.1.2-1ubuntu2.28(Ubuntu).
An old number in the header is therefore no proof of an open vulnerability, and a new number in php -v no proof of a restart: the command line loads the installed package on every call, while a running FPM service keeps working with the old code until it is restarted. If the header carries a distribution package suffix, the level can be compared with that distribution's security page; without a suffix, only a look at the server helps. The cockpit accounts for this with the "backport possible" marker, which it sets for PHP, nginx, Apache httpd and OpenSSL. The CRA cockpit documentation describes the caveat in detail.
Zero potentially outdated components means: no visible version is below a stored threshold. It does not mean that PHP2Shell is closed. An unpatched 8.3 or 8.4 produces no finding there, a hidden version no result. The patch check with php -v and the distribution's security notice does not replace the inventory, and the inventory does not replace the patch check.
Step 4: Patch and restart
This article is not a patch guide, but three points from the advisories belong on every list. First, the PHP project gave the fixes to Linux distributions and long-term support vendors in advance and refers to them for updated packages (PHP Group). If you get PHP from the package manager, you wait for the distribution's package. Second, according to the BSI advisory, you check the patch level with php -v and compare it against the advisory (BSI). Third, containers with PHP are rebuilt instead of only updating the host (BSI).
A new package only takes effect once the running PHP processes have been restarted: the FPM service, the Apache server with mod_php, the workers of an application server. The PHP project's interim mitigations say so explicitly for changed settings, instructing you to restart every worker (PHP Group). The same applies to a package update. The list should therefore record the date of the restart alongside the date of the update, for example from the start time of the service.
If you plan a restart during operation, you can set a maintenance window in uptime monitoring. Alerts stay silent during this time, while the checks keep running and count toward availability. This keeps it visible in the log whether the website was reachable again after the window.
Step 5: Check after the restart
After patch and restart, two questions can be answered from the outside: Is the website reachable, and does it look the way it did before? A PHP update can change extensions, reset a configuration or keep a service from starting again. That is no reason to skip the patch, but it is a reason to look afterwards. In its advisory, CERT-EU speaks of a fix that has been applied and verified (CERT-EU). How to re-measure a change to a running system and roll it back if needed is covered in the article on deploy errors as a cause of outages.
Uptime monitoring checks from several measuring nodes and only alerts once several nodes confirm an outage. An FPM service that does not start after the restart is caught without manual work.
The screenshot changelog compares new captures with the previous ones and highlights changed areas. A page that only shows an error message after the update appears as a change in the next capture.
The next scan reads the headers again. If the PHP version is visible, the cockpit shows the new level with the time of the check; with a hidden version, PHP does not appear there at all, and the record comes from the inside.
One limit applies here too: from the outside, you cannot tell whether a server was compromised before the patch. For this, the BSI names checks on the server itself, such as searching for newly created or modified PHP files, executables and possible web shells (BSI), and watching for unusual processes started by the web server (BSI). The screenshot comparison would show a visible defacement of the page, but not a quietly planted backdoor.
Step 6: Record the state
In the end, there is a list that states for each website what was checked, what was done and what was verified. In the cockpit, each finding per component can be marked as known, for example the end-of-life finding for PHP 8.1 on a server whose package the distribution has demonstrably fixed. The time of the acknowledgment is stored, and it can be withdrawn. The reasoning, i.e. package level and restart date, belongs in your own list. The component list can also be exported as a CycloneDX file. For a given date, that is a useful snapshot, even though it only shows what is visible from the outside; the difference from a complete software bill of materials is covered in the article on the SBOM under the CRA.
For the client or management, a simple table or one file per occasion is often enough. An example of what the entries per website can look like:
occasion: PHP2Shell (CVE-2026-109618, CVE-2026-109619)
basis: BSI BITS-H 2026-297981-1232, version 1.2
sites:
- address: shop.example
hosting: own server, Apache with mod_php
php_before: "8.1.31, header visible"
action: move to 8.3, distribution package
restart: 2026-10-22 07:41
check: reachable, screenshot unchanged
owner: agency
- address: www.example
hosting: managed server at the host
php_before: "hidden, 8.2 according to host"
action: "package 8.2.35-1~deb12u1 according to host"
restart: "2026-10-21 according to host ticket"
check: reachable, screenshot unchanged
owner: host
open:
- staging environments without monitoring
The distinction between measured and stated matters. "Reachable" and "screenshot unchanged" are measurements with a timestamp. "8.2 according to host" is information provided by someone else and should be labeled as such. Mixing the two leaves you, in case of dispute, with a list that does not show what it is based on. Open items belong on it explicitly instead of being left out.
The process stays, the vulnerability changes
PHP2Shell will not have been the last critical vulnerability in the web stack. Just two days after the patches, the PHP project announced another vulnerability, CVE-2026-115560, with an interim mitigation; it only affects unusually configured applications and will be fixed in the regular release cycle (PHP Group). CERT-EU updated its advisory accordingly on October 23 (CERT-EU). The BSI considers it possible that further vulnerabilities will be discovered because of the increased attention on PHP (BSI).
This week's list is therefore not a throwaway product. It will be needed again at the next occasion, for PHP, for the web server, for a library in the front end. If you keep it current, you answer the question about affected websites next time from the list instead of from memory. How to choose suitable vulnerability feeds is described in the article on EUVD and CVE; which header locks camera, microphone and location is shown in the article on the Permissions-Policy.
For agencies, the process is also a service you can show to the client: a dated state per website instead of a circular email saying "all done". How XICTRAQ brings several client websites together in one account is explained on the page for agencies. The process in brief:
- Compare the inventory from contracts, DNS and hosting accounts with monitoring.
- Record PHP branch, hosting and responsibility per website, and fill in hidden versions from the inside.
- Branches without security updates first, then hidden versions, then check the patch level of supported branches.
- Apply the distribution package or fixed version, rebuild containers, restart services.
- Check reachability and appearance after the restart, and arrange checks on the server.
- Record measured and stated information separately and with a date, and name open items.
This article is based on: BSI, security advisory "PHP: Kritische Schwachstellen bedrohen Webanwendungen weltweit", BITS-H no. 2026-297981-1232, version 1.2 of October 22, 2026; PHP Group, advisories of October 21 and 23, 2026 in the news archive, plus the overviews "Supported Versions" and "Unsupported Branches"; PHP manual on expose_php; ENISA, "Joint statement on critical PHP vulnerabilities" of October 21, 2026; CERT-EU, Security Advisory 2026-018; Debian Security Tracker and Ubuntu Security on CVE-2026-109618; HTTP Archive, Web Almanac 2025, Security chapter. Product information is based on XICTRAQ® feature pages and documentation as of October 2026.
Does XICTRAQ detect whether a website is affected by PHP2Shell?
php -v together with the distribution's security notice.