PHP2Shell: Millions of Servers at Risk. Is Yours Secure?
Two critical PHP vulnerabilities have put millions of internet-facing services at risk. Discover what PHP2Shell is, why urgent patching matters, and how to investigate your Linux server for signs of compromise using my free, open-source security auditing script.
Published 22 Oct 2026, 05:30 BST · Last edited 22 Oct 2026, 05:57 BSTShare this page ↗
By Marcus Cicero | Cybersecurity, Linux, PHP
Yesterday, two critical vulnerabilities in PHP prompted an urgent security update across the web. If you run a WordPress website, manage a VPS, administer a dedicated server or look after websites for other people, this is one of those occasions when “I'll update it at the weekend” really isn't a great plan.
The vulnerabilities, CVE-2026-109618 and CVE-2026-109619, have been nicknamed PHP2Shell. Both are rated 9.2 (Critical) under CVSS v4.0. In certain circumstances, they can allow someone on the internet to execute code on a vulnerable server without a username or password.
I patched all the Linux servers that I manage and maintain as soon as the fixes became available. I then asked myself a very important question. What if somebody had already got in? That prompted me to put together a free Linux intrusion-triage script, which I'll explain later in this article.
What exactly is PHP2Shell?
PHP is the server-side language behind an enormous part of the web, including WordPress, Drupal, Joomla and countless bespoke business applications. Usually, when somebody visits a PHP-powered website, the server processes their request and returns a page or some data.
PHP2Shell exploits problems inside the PHP engine itself, rather than a poorly written WordPress plugin or an application with a weak password. This means a fully updated website can still be at risk if its underlying PHP runtime is vulnerable.
CVE-2026-109618: memory corruption after an out-of-memory error
PHP can encounter an out-of-memory condition while processing a request. In vulnerable versions, some internal structures may not be completely initialised before PHP attempts to clean up. Under carefully crafted conditions, the engine can end up acting on invalid memory.
In plain English, imagine a filing system that marks a folder as complete before all its contents have actually been filed. If something interrupts the process, the clean-up routine trusts information that was never properly prepared. Researchers showed that an attacker can deliberately exploit this type of confusion to achieve remote code execution.
CVE-2026-109619: stale memory carried between requests
The second problem involves PHP retaining references to memory belonging to a previous request, even after that memory has been released. A later request handled by the same worker may encounter that stale information. This is a form of use-after-free vulnerability and can lead to memory disclosure or code execution.
Think of it as handing the next visitor a key that points to a room which has already been cleared out and reassigned. The key should no longer work, but the system has failed to forget it.
Importantly, PHP's own security team says the risk is particularly high with Apache's mod_php configuration, where an unauthenticated request can trigger exploitation before application code runs. PHP-FPM, php-cgi, FrankenPHP and LiteSpeed deployments also require attention.
Why is this so serious?
Remote code execution (RCE) means an attacker may be able to make the server perform actions it was never supposed to perform. Successful exploitation generally gives code execution with the permissions of the affected web worker, not automatically root access. But even those permissions can be enough to cause substantial damage.
- Steal information: potentially access application files, credentials, database connection details or sensitive process memory.
- Alter websites: modify pages, interfere with applications or install a web shell if filesystem permissions permit.
- Interrupt services: crash PHP workers or disrupt websites and applications.
- Attempt to stay hidden: add persistence mechanisms or use stolen credentials to reach other services.
- Move further: look for additional weaknesses that could allow broader control of the host or connected systems.
A firewall or web application firewall may block known attack patterns, but it is not a substitute for patching. Likewise, updating WordPress itself does not fix a vulnerability in PHP's runtime.
How many servers could be affected?
Here's the figure that really brings home the scale. Palo Alto Networks' Cortex Xpanse identified more than 22.6 million internet-exposed instances potentially vulnerable to these two flaws, based on its telemetry at the time of publication.
That is an exposure estimate, not evidence that 22.6 million machines have been hacked. An exposed instance is not necessarily a unique physical or virtual server. Hosting arrangements, multiple services, incomplete visibility and detection methods all complicate the count. Nor does detecting PHP necessarily prove that a particular deployment is exploitable.
For broader context, W3Techs reported that PHP was used by approximately 69% of websites whose server-side programming language it could identify in October 2026. Again, that's a measure of websites, not a count of distinct servers or confirmed vulnerable installations.
The responsible conclusion is that the potential attack surface is enormous, but the number of successfully compromised servers is not known. Claims that tens of millions of servers have already been hacked would be misleading.
Was anyone exploiting PHP2Shell before the patches arrived?
Yes, there is evidence of attempted exploitation before public disclosure. According to Amazon Threat Intelligence, its MadPot honeypot network recorded a PHP2Shell exploitation attempt on 17 October 2026, four days before the coordinated public release on 21 October. AWS subsequently observed further attempts and reported broader exploitation activity against its sensors.
A honeypot observation is not the same as a confirmed compromise of a real customer server. Nevertheless, it gives administrators a practical starting point. Review relevant logs from at least 17 October, not just from the day you installed the patch. Where logs are available, examining a longer period is sensible.
Which PHP versions need updating?
On 21 October 2026, the PHP project issued emergency fixes for its supported branches:
| PHP branch | Fixed upstream release |
|---|---|
| PHP 8.2 | 8.2.35 |
| PHP 8.3 | 8.3.36 |
| PHP 8.4 | 8.4.27 |
| PHP 8.5 | 8.5.12 |
PHP 8.1 and older no longer receive normal upstream security releases. However, some Linux distributions and hosting vendors have supplied backported fixes. That means an older version number can still be patched, provided your vendor explicitly confirms the fix is present. If you're on an unsupported build with no maintained backport, upgrading is essential.
If you use cPanel/WHM, check both EasyApache's PHP packages and cPanel's own internal PHP. cPanel published separate fixes for both, including backports for its supported older EasyApache versions. Containers, alternative PHP installations and bundled runtimes also need checking independently.
One common trap: Running php -v tells you about the command-line PHP binary selected by your shell. It does not necessarily identify the version serving each website. Verify the PHP handlers or FPM pools your applications actually use, then restart the relevant workers after updating.
Patching is essential. But how do you know nobody got in first?
A patch closes the underlying vulnerability. It does not automatically remove a malicious file, unauthorised SSH key or persistence mechanism that somebody might already have planted. And some attacks may leave no obvious file behind at all.
That's why, after updating my own servers, I developed Linux Intrusion Triage v1.0. A free open-source Bash script that helps Linux administrators look for signs worthy of further investigation.
It is designed for common Linux distributions, including Ubuntu, Debian, AlmaLinux, Rocky Linux, RHEL and Fedora. It is not a PHP2Shell exploit scanner, and it does not attempt to attack your applications to determine whether they're vulnerable. Instead, it collects general evidence that might suggest an intrusion, whether the entry point was PHP2Shell or something else.
What does the script check?
- Unexpected accounts with root-level privileges and unusual system accounts.
- SSH configuration and recent changes to authorised-key files.
- Changes to cron jobs, systemd services and other persistence locations.
- Processes running from temporary directories or from executables that have been deleted.
- Recently changed executable files in temporary directories.
- Listening network services and available authentication-log excerpts.
- Changes to files in website or application directories you choose to monitor.
- Optional package-file verification using RPM or Debian's package tools.
The script is read-only with respect to the system it examines. It does not remove malware, change permissions, install packages or transmit information over the internet. It does create a private directory containing its reports, so it is not literally a zero-write operation.
How to download and run Linux Intrusion Triage
Step 1: Download the archive from the link below and transfer it to the Linux machine you want to check. The download contains the script, a README and an MIT licence.
Download Linux Intrusion Triage v1.0 (.tar.gz)
Step 2: Extract it. From the directory containing the archive:
tar -xzf linux-intrusion-triage-v1.0.tar.gz
Step 3: Review the code before running it as root. You should inspect any security script, including one I've written, before giving it administrative privileges.
less linux-intrusion-triage.sh
Step 4: Run a standard scan. This example checks recent activity over a 14-day window and writes its report under /root:
sudo bash ./linux-intrusion-triage.sh \
--days 14 \
--output-parent /root
If you also manage a website, you can ask the script to inspect its files. Replace /var/www with the actual document root or application directory:
sudo bash ./linux-intrusion-triage.sh \
--days 14 \
--watch-dir /var/www \
--output-parent /root
You can repeat --watch-dir for multiple locations. On a hosting server, you might watch selected sites beneath /home instead. Be selective on busy servers. Hashing large directory trees can take time.
For a more thorough but potentially slower package-integrity check, add --deep:
sudo bash ./linux-intrusion-triage.sh \
--days 14 \
--deep \
--output-parent /root
Run deeper scans during a suitable maintenance window if the machine is heavily loaded.
Understanding the results
When the scan finishes, it prints the location of a private report directory, with files such as summary.txt, findings.tsv, baseline.tsv and supporting evidence. Start with summary.txt.
The findings use three labels:
- HIGH: something that deserves prompt investigation, such as an unexpected UID-0 account.
- REVIEW: unusual activity or a change that may have a completely legitimate explanation.
- INFO: useful context, configuration observations or checks the script could not fully perform.
None of these labels confirms an intrusion. Software upgrades, administrator changes and ordinary system maintenance can all produce findings. Equally, a clean report is not a guarantee that a machine is safe. Attackers may erase logs, disguise timestamps, operate entirely in memory or interfere with tools running on a compromised host.
Reports may contain usernames, IP addresses and sensitive operational details. Keep them private, and redact them before asking for help publicly.
An even better approach: build a baseline
The most useful question in security is often not “Does this file look suspicious?” but “Has this changed since the system was last known to be healthy?”
Each scan produces a baseline.tsv containing checksums and other information about selected files and system state. Keep a copy of a trusted, known-good baseline securely, ideally somewhere other than the server being monitored. On a later scan, compare against it:
sudo bash ./linux-intrusion-triage.sh \
--days 14 \
--watch-dir /var/www \
--compare /root/previous-scan/baseline.tsv \
--output-parent /root
Replace the baseline path with the real location, and use the same watched directories as your earlier scan. The script generates baseline.diff showing changes worth reviewing. A legitimate website update will change files too; the comparison tells you what changed, not why.
What if the script finds something genuinely suspicious?
Don't immediately delete everything it flags. Preserve relevant logs and, where possible, take a provider-level snapshot before changing the machine further. If you have credible evidence of unauthorised code execution, consider isolating affected services, assessing exposed credentials and investigating from trusted systems.
If an attacker may have obtained root access, an on-host script cannot reliably prove the machine is clean. In that situation, a carefully planned rebuild from known-good media or backups may be safer than attempting to remove a few suspicious files.
The bigger lesson
PHP2Shell is a reminder of how much of our digital lives depends on shared pieces of software that most people never see. A vulnerability in a single runtime can have consequences for businesses, charities, governments, online shops and personal websites around the world.
The practical response is straightforward. Patch promptly, confirm you're patching the PHP version actually in use, inspect for earlier compromise and maintain a reliable baseline.
For me, the most important lesson is this: Patching closes the door, but it doesn't tell you whether somebody walked through it yesterday. That's exactly why I've made Linux Intrusion Triage freely available.
Linux Intrusion Triage v1.0 is released under the MIT licence. It is a general-purpose investigation aid, not a substitute for professional incident response or a guarantee that a system is uncompromised. This article reflects information available on 22 October 2026.
References and further reading
- PHP Project: 21 October 2026 critical security advisory and patched releases
- PHP security advisory: CVE-2026-109618
- PHP security advisory: CVE-2026-109619
- Palo Alto Networks Unit 42: exposure estimate
- AWS Security Blog: observed exploitation attempts from 17 October
- cPanel: PHP2Shell updates and backports
- W3Techs: PHP usage statistics