Skip to content
GDPR compliant. Hosted in the EU.
14-day free trial →
BSI advisoryComponent inventoryAgencies
Security 17 min read 9 Nov 2026

PHP2Shell: Find Affected Websites with an Inventory

After the BSI warning on PHP2Shell: how agencies find every PHP website, rank it by end of life, check it after a restart and keep a dated record of the state.

X

XICTRAQ®

XICTRAQ®

PHP2ShellComponent inventoryAgencies
9.2 of 10
CVSS score per PHP2Shell vulnerability, CVSS version 4.0 (BSI)
23.9 %
of hosts crawled by the HTTP Archive send X-Powered-By (Web Almanac 2025)
Dec 31, 2026
security updates for PHP 8.2 end (PHP Group)
PHP2Shell: find affected websites with an inventoryFrom the full estate to a priority order, from restart to recordAll websitescontracts, DNS, hosting accountsPHP detectedheaders, CMS, session cookieVersion visiblenumber in X-Powered-ByEnd of life firstno security fixesWebsitePHPVersionStatusportal.examplefixed release8.48.4.27visiblewww.exampleno X-Powered-By––hiddenblog.exampledistribution package8.38.3.6backport possibleshop.examplebranch without updates8.18.1.31visibleSample data · confirm the patch level per site with php -vChecked after restart: reachable, unchangedUptime · screenshot comparison · dated noteEnd of life per PHP Group · trigger: BSI security advisory on PHP2Shell
On October 21, 2026, the PHP project closed two critical vulnerabilities in the PHP runtime (PHP Group) that coverage has labeled PHP2Shell. The German Federal Office for Information Security (BSI) rates the situation at criticality 3 / orange in its security advisory (BSI). For an agency or an operator of several websites, the work that follows does not start with the patch but with a plain question: Which websites run on PHP, on which branch, with which host, and who applies the update? This article describes a process that holds up after every critical vulnerability in the web stack: inventory, priority by end of life, patch, restart, check and record. It also shows where the outside view ends.

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.

Context without alarm

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 -v and 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.

$ curl -sI https://shop.example/ | grep -iE '^(server|x-powered-by)'
server: Apache x-powered-by: PHP/8.1.31
$ curl -sI https://www.example/ | grep -iE '^(server|x-powered-by)'
server: nginx

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.

Hidden version: no contradiction

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 branchSecurity updates untilVersion with PHP2Shell patchPriority in the list
5.x to 7.3ended years agoonly via long-term support vendorsfirst, plan the upgrade
7.4 and 8.0ended Nov 28, 2022 and Nov 26, 2023source backport or distribution packagefirst, plan the upgrade
8.1ended Dec 31, 2025source backport or distribution packagefirst, plan the upgrade
8.2Dec 31, 20268.2.35high, plan the move as well
8.3Dec 31, 20278.3.36check patch level
8.4Dec 31, 20288.4.27check patch level
8.5Dec 31, 20298.5.12check patch level
unknownunknownunknownclarify 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.

What a zero in the cockpit does not mean

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).

$ php -v | head -n 1
PHP 8.3.6-0ubuntu0.24.04.13 (cli) (built: Oct 21 2026 10:12:44) (NTS)
$ dpkg -l 'php8.3-*' | awk '/^ii/ {print $2, $3}' | head -n 3
php8.3-cli 8.3.6-0ubuntu0.24.04.13 php8.3-common 8.3.6-0ubuntu0.24.04.13 php8.3-fpm 8.3.6-0ubuntu0.24.04.13
$ sudo systemctl restart php8.3-fpm && systemctl show -p ActiveEnterTimestamp php8.3-fpm
ActiveEnterTimestamp=Thu 2026-10-22 07:41:09 CEST

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.

Reachable

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.

Unchanged

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.

Version

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:

php2shell-record.yaml
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:

  1. Compare the inventory from contracts, DNS and hosting accounts with monitoring.
  2. Record PHP branch, hosting and responsibility per website, and fill in hidden versions from the inside.
  3. Branches without security updates first, then hidden versions, then check the patch level of supported branches.
  4. Apply the distribution package or fixed version, rebuild containers, restart services.
  5. Check reachability and appearance after the restart, and arrange checks on the server.
  6. Record measured and stated information separately and with a date, and name open items.
Sources and studies

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?
No. XICTRAQ only sees what the server shows from the outside and assesses visible PHP versions with an offline heuristic that does not contain the PHP2Shell identifiers. It does not assess the patch level within branches 8.2 to 8.5. XICTRAQ supplies the account-wide list with the externally detected tech stack and marks visible end-of-life PHP branches; whether a server is patched is usually settled by php -v together with the distribution's security notice.
Is it enough to update WordPress, Shopware or TYPO3?
According to the BSI advisory, no. The vulnerabilities lie in the PHP runtime itself and not in specific applications (BSI). An up-to-date CMS is still sensible but does not close this vulnerability; the PHP package on the server has to be updated as well and the service restarted.
Our header shows PHP 8.3.6. Does that mean the website is unpatched?
Not necessarily. Distributions often apply fixes without raising the base version; Ubuntu 24.04 LTS ships the fix for CVE-2026-109618 in package 8.3.6-0ubuntu0.24.04.13 (Ubuntu). What counts is comparing the installed package with the distribution's security notice, as the BSI also suggests (BSI).
Should we turn X-Powered-By back on so the inventory sees the version?
Usually not. The visible version number helps attackers just as much as monitoring. It is more practical to keep the version hidden and enter the level for these websites into the list from the inside. In the cockpit, PHP is missing entirely for such websites; "not assessable" only appears there if not a single component reveals a version. Mark them explicitly in your own list so they do not slip through as inconspicuous.
Which websites should be handled first?
Typically websites on branches without security updates come first, i.e. before PHP 8.2 (BSI), then websites with a hidden version, and finally the supported branches where only the patch level needs checking. Within each group, the European agencies recommend giving priority to systems connected to the internet (ENISA).
How do we show clients that the patch has been applied?
A list per website with package level, date of the update, date of the restart and the check afterwards has proven useful. Reachability and appearance can be measured with dates using monitoring and screenshot comparison, and in the cockpit each finding can be marked as known with a timestamp. Information from the host should be labeled as such, not as your own measurement.
Start in 60 seconds

Let XICTRAQ® watch your website.

Free plan with no fixed term available. No credit card, no installation, no hidden fees.