At 21:33 CEST on Tuesday, 20 October, PHP pre-announced two critical vulnerabilities, with a fix due the next afternoon. A hosting provider running cPanel servers read that notice and saw the problem straight away. The fix would cover PHP 8.2 to 8.5 only. The sites hosted on their servers run every PHP version from 5.2 up, because each site stays on the version its application was built for.
PHP’s release would fix four branches. Those servers run 16.
The standard PHP security advice is to run a supported version and wait for your vendor. By the time TechCrunch called the week the “PHP-ocalypse“, that advice had a visible gap: somebody has to own the branches upstream has dropped. During PHP2Shell (CVE-2026-109618 and CVE-2026-109619), CloudLinux did.
CloudLinux shipped fixed ea-php (cPanel’s EasyApache PHP builds) and alt-php (CloudLinux’s PHP builds behind PHP Selector) for all 16 branches from 5.2 to 8.5, plus native PHP packages for every affected version.
The Imunify360 web application firewall (WAF) had been blocking the public exploit since the morning of 21 October, hours before PHP’s fix.
What PHP2Shell is (CVE-2026-109618 and CVE-2026-109619)
PHP2Shell is two remote code execution flaws in PHP itself, both scored 9.2 on CVSS v4.0 and neither needing a login.
In CVE-2026-109618, PHP runs out of memory mid-request, and cleanup treats the half-built data as valid. In CVE-2026-109619, one request’s state survives after its memory is freed, and the next request on the same worker can use it.
PHP2Shell sits below the application. PHP reads the request before the site’s code runs, so any PHP script on the server will do, whether or not it handles forms. The site’s own PHP application security never gets a say because the flaw triggers before that code starts.
PHP lists every web-facing setup as affected (PHP-FPM, mod_php, php-cgi, FrankenPHP, and LiteSpeed) and rates the risk highest on Apache with mod_php.
The exploit toolkit came first.
Details leaked on 20 October, and a public tool, also called PHP2Shell, went live before the fix. It abuses session upload progress, which is on by default. Some requests carry a User-Agent starting php2shell-, but about two-thirds of those carrying the tool’s multipart boundary used a different one.
| PHP branch | What the PHP project shipped on 21 October | Fixed version |
|---|---|---|
| 8.5 | Release | 8.5.12 |
| 8.4 | Release | 8.4.27 |
| 8.3 | Release | 8.3.36 |
| 8.2 | Release | 8.2.35 |
| 8.1, 8.0, 7.4 | Minimal source backports in the advisory; no release | No php.net release |
| 7.3 and older | Nothing | No php.net release |
Sources: PHP security advisory; the CloudLinux advisory for CVE-2026-109618 and CVE-2026-109619.
Why a hosting server cannot just upgrade
The nine guides that ranked for PHP security on 26 October all end on the same instruction: run a supported version. On a shared hosting server, that advice reaches the wrong person.
A shared server holds hundreds of accounts, each pinned to the PHP version its application was written for. A shop module that breaks on PHP 8 doesn’t care about php.net’s calendar.
That is why PHP Selector, which lets each account pick its PHP version, supports PHP 5.2 to 8.5.
The provider can’t force everyone onto PHP 8.4. Forced upgrades break sites, and broken sites come back as tickets and churn. Providers already pay for it: 53% name outdated or vulnerable software as their top security challenge, and security incidents take 35% of their support time.
So when PHP says “upgrade,” a hosting provider hears a different question. Who patches the version my customer is stuck on, and how fast?
Inside the response: 20 to 23 October
Imunify360 telemetry recorded the first request from the public exploit tool at 01:33 CEST on 21 October, four hours after PHP’s notice and 14 hours before its fix. From about 10:20, scanning scaled up sharply, and by 13:00 requests naming the PHP2Shell exploit tool had reached more than 3,600 servers in the Imunify360 network.
The WAF got there first. At 11:10, Imunify360 ruleset 8.83 reached stable and blocked the known exploit request on ModSecurity and Coraza, about 4.5 hours before PHP’s fix. The rule matches how the request is built, not the tool’s name, so requests that hid the name were blocked too.
Around noon, an IP reputation rule began sending exploiting addresses to a CAPTCHA on every protected server. Over three days, five ruleset releases extended blocking to LiteSpeed, caught renamed variants of the tool, added a logging rule for malformed session cookies, and blocked a serialized object in the upload progress field. The Imunify360 coverage table by web server shows what each setup had, and when.
From 21 to 26 October, the dedicated PHP2Shell rules matched about 9 million times. Blocking rules accounted for about 6.25 million of those matches, and 99% of them were on requests the WAF denied. The public tool’s fingerprint appeared in 62% of all matches.
PHP released 8.2.35, 8.3.36, 8.4.27, and 8.5.12 at 15:45. That left four released fixes to package, source backports for 7.4, 8.0, and 8.1, and nothing for the nine branches from 5.2 to 7.3. The build team paused other builds and wrote the missing fixes itself.
The result covered every branch a hosting server runs. Fixed ea-php shipped for all 16 branches, ea-php52 to ea-php85, on CloudLinux 7 to 10. Fixed alt-php shipped for all 16 branches on CloudLinux 7, 8, and 9. Native PHP packages followed for every affected version, and TuxCare Endless Lifecycle Support (ELS) released packages for alt-php, distribution PHP, and PHP for Windows. Each arrived as a normal package update.
What shipped for PHP2Shell
| Build | Branches fixed | Where |
|---|---|---|
| ea-php (cPanel EasyApache) | 16: ea-php52 to ea-php85 | CloudLinux 7, 8, 9, and 10 |
| alt-php (PHP Selector) | 16: 5.2 to 8.5 | CloudLinux 7, 8, and 9 |
| Native PHP (distribution packages) | Every affected version | CloudLinux 7 to 10 |
| TuxCare ELS for PHP | alt-php, distribution PHP, and PHP for Windows | ELS repositories |
| php.net-numbered rebuilds | alt-php and ea-php 8.2 to 8.5 | alt-php on CloudLinux 7, 8, and 9; ea-php on CloudLinux 7 to 10 and CloudLinux for Ubuntu 22.04 |
Source: the CloudLinux advisory, which lists every fixed package and version.
Timeline: PHP2Shell response, 20 to 23 October 2026 (CEST)
| When (CEST) | Lane | Event |
|---|---|---|
| 20 Oct 21:33 | Disclosure and attack | PHP pre-announcement |
| 21 Oct 01:33 | Disclosure and attack | First exploit request |
| 21 Oct 10:20 | Disclosure and attack | Mass scanning starts |
| 21 Oct 11:10 | Imunify360 WAF | Ruleset 8.83 blocks the known exploit request |
| 21 Oct 12:00 | Imunify360 WAF | IP reputation CAPTCHA |
| 21 Oct 15:18 | Imunify360 WAF | Ruleset 8.84 adds LiteSpeed |
| 21 Oct 15:45 | Reference | PHP releases its fix (8.2.35, 8.3.36, 8.4.27, 8.5.12) |
| 21 Oct 19:17 | Imunify360 WAF | Ruleset 8.85: renamed variants |
| 21 Oct 22:55 | Fixed PHP packages | ea-php 5.2 to 8.5 |
| 22 Oct 02:07 | Fixed PHP packages | alt-php in stable |
| 22 Oct 07:50 | Imunify360 WAF | Ruleset 8.86: more variants |
| 22 Oct 21:50 | Fixed PHP packages | Native PHP, all versions |
| 23 Oct 02:08 | Fixed PHP packages | alt-php with php.net version numbers |
| 23 Oct 10:40 | Imunify360 WAF | Ruleset 8.88: serialized object |
Everything in the WAF lane before 15:45 on 21 October was in place before PHP released its fix.
Not all of it went well. The first fixed alt-php and ea-php packages kept their old version numbers, so scanners flagged patched servers as vulnerable. On 21 October, we announced fixed alt-php for CloudLinux while it sat only in the TuxCare ELS repository; the correction took about three hours (customers hit the gap before the correction went out).
Servers with the WAF off, in log-only mode, or running ImunifyAV, Imunify’s malware scanner, had no WAF protection. As of 26 October, the blocking rules still target the upload progress path that the public exploit uses. The out-of-memory path of CVE-2026-109618 is covered by logging rules that measure its likely request shapes, but not yet by a blocking rule.
A change is already in place. alt-php and ea-php for 8.2 to 8.5 were rebuilt with php.net version numbers on 23 October.
The status page incident keeps the full record.
Who patches PHP after PHP stops
Three layers patch PHP, and each stops somewhere different.
- The PHP project releases fixes for supported branches, this time 8.2 to 8.5, and publishes source backports without releases for a few older ones.
- Linux distributions ship fixes for the PHP versions in their own repositories, on their own schedule.
- The third layer is a vendor that owns the branch: it writes, builds, and tests the fix for versions upstream won’t touch, and ships it through the server’s package manager.
The OWASP PHP Configuration Cheat Sheet makes a fair point: extended support from a distribution or vendor does not make a branch “supported.” We agree. A backported fix leaves PHP 7.4 outside php.net’s policy. It closes the CVE on the exact version the site runs, so the upgrade can happen on the customer’s schedule instead of the CVE’s.
HardenedPHP, the backported patch set included in CloudLinux and Imunify360, carries security fixes to end-of-life PHP 5.x, 7.x, and 8.x as drop-in packages that work with PHP Selector. If you already run CloudLinux or Imunify360, it covers your end-of-life PHP today.
ELS for PHP is the same technology sold standalone for the rest of the fleet, on 20 platforms: EL6 to EL10, Ubuntu 16.04 to 26.04, Debian 10 to 13, Alpine 3.23 and 3.24, and Windows Server 2019, 2022, and 2025.
PHP’s release fixed four branches; we shipped fixes for 16.
The PHP lifecycle, and what expires next
PHP 8.2 reaches end of life on 31 December 2026, nine weeks after this post.
After that, the next PHP CVE gets no php.net release for 8.2, whatever its score. Since PHP 8.1, each branch gets about two years of active support and two more years of security-only fixes, ending on 31 December.
| PHP branch | Security support ends (php.net) | Status on 26 Oct 2026 | Who patches it after that |
|---|---|---|---|
| 8.5 | 31 Dec 2029 | Supported | PHP project |
| 8.4 | 31 Dec 2028 | Supported | PHP project |
| 8.3 | 31 Dec 2027 | Security fixes only | PHP project |
| 8.2 | 31 Dec 2026 | Security fixes only; ends in nine weeks | PHP project until 31 Dec, then distributions for their own packages and HardenedPHP / ELS for PHP |
| 8.1 | 31 Dec 2025 | End of life | Distributions for their own packages; HardenedPHP / ELS for PHP |
| 8.0 | 26 Nov 2023 | End of life | Same |
| 7.4 | 28 Nov 2022 | End of life | Same |
| 7.3 | 6 Dec 2021 | End of life | Same |
| 5.6 | 31 Dec 2018 | End of life | Same (alt-php and ea-php patch back to 5.2) |
Sources: php.net supported versions and end-of-life branches, read 26 October 2026.
PHP security practices that hold up on a shared server
Most PHP security best practices still apply on a shared server.
What changes is who owns each one. The provider sets some fleet-wide in php.ini, while others live in the customer’s code.
PHP2Shell is a useful test: almost none of them stopped it.
| Practice or PHP configuration | What it stops | Against PHP2Shell | Who owns it on a shared server |
|---|---|---|---|
| Patched PHP build | The CVE itself | The only complete fix | Provider installs it; whoever owns the branch builds it |
| WAF in blocking mode | Known exploit requests | Blocked the public exploit’s upload progress path from ruleset 8.83; no rule for the out-of-memory path of 109618 | Provider; log-only mode protects nothing |
| session.upload_progress.enabled = 0 | The upload progress feature | PHP’s interim measure for 109619. Since 23 October, PHP advises keeping it off until its next regular release because of CVE-2026-115560 | Provider, in php.ini or the PHP-FPM pool; not ini_set() or .user.ini |
| Memory and request-size limits (memory_limit, post_max_size, max_file_uploads) | Oversized requests and uploads | PHP’s advisory gives settings for the out-of-memory flaw; apply them as it describes | Provider |
| Per-account isolation (CageFS, a virtualized filesystem for each account) | A compromise spreading between accounts | Contains it; doesn’t prevent it | Provider |
| disable_functions (exec, system, shell_exec, passthru) | Shell commands from injected PHP | No: the flaws trigger while PHP reads the request | Provider, per PHP version |
| open_basedir | Scripts reading outside allowed paths | No, same reason | Provider, per account |
| allow_url_include = Off, allow_url_fopen | Remote file inclusion (RFI) | No | Provider |
| expose_php = Off | Version disclosure in headers | No: scanners sprayed every server | Provider |
| display_errors = Off, log_errors = On | Stack traces shown to visitors | No | Provider default; site owner can override |
| session.cookie_httponly, session.cookie_secure, session.use_strict_mode | Session hijacking and fixation | No | Provider default; site owner can tighten |
| Prepared statements | SQL injection | No | Site owner |
| Output escaping and Content Security Policy (CSP) | Cross-site scripting (XSS) | No | Site owner |
| CSRF tokens | Cross-site request forgery | No | Site owner |
Full directive reference: the OWASP PHP Configuration Cheat Sheet. Vulnerability classes: TuxCare’s guide to common PHP vulnerabilities.
How to test whether a server is fixed
Run this PHP security test for every PHP version the server serves.
Step 1. Check each build’s changelog for the CVE IDs (commands below; repeat for each installed alt-php and ea-php version, and use dpkg -l for ea-php on Ubuntu). Rebased native packages name no CVE, so check for 8.2.35, 8.3.36, or later instead. If fixed packages don’t appear, confirm cloudlinux-release is current.
rpm -q --changelog alt-php85-common | grep -E 'CVE-2026-(109618|109619)'
rpm -q --changelog ea-php84-php-cli | grep -E 'CVE-2026-(109618|109619)'
dpkg -l ea-php84-php-cli # CloudLinux for Ubuntu: compare the version with the fixed list
rpm -q --changelog php-cli | grep -E 'CVE-2026-(109618|109619)'
rpm -q php-cli # rebased native builds: 8.2.35 or later on 8.2, 8.3.36 or later on 8.3
rpm -q cloudlinux-release # if the update fails or finds nothing to install
Step 2. Restart PHP-FPM or the web server after updating. A patched package doesn’t fix workers that are already running. For ea-php on cPanel:
/scripts/restartsrv_httpd
/scripts/restartsrv_apache_php_fpm
Step 3. Keep session upload progress off. Set session.upload_progress.enabled = 0 in php.ini or the PHP-FPM pool (php_admin_value), where accounts can’t override it; a .user.ini can switch it back on. PHP first gave this as an interim measure for PHP2Shell. On 23 October, it extended the advice to patched servers: a third session flaw, CVE-2026-115560, will be fixed only in PHP’s next regular release. It needs an unusual setup, an application that switches session.serialize_handler to php at runtime, so applications that never do that can keep the feature on. Restart PHP, confirm the effective value on a phpinfo() page for each version, and remove the page afterwards; php -i shows command-line settings, which can differ. PHP’s advisory gives separate memory and request-size settings for the out-of-memory flaw.
Step 4. Confirm the Imunify360 WAF is on, in blocking mode, and on ruleset 8.88 or later. The path below is for cPanel with Apache; other panels and LiteSpeed use different paths. Run as root:
cat /etc/apache2/conf.d/modsec_vendor_configs/imunify360-full-apache/VERSION
imunify360-agent update --force modsec-rules # if older than 8.88, then check again
Step 5. Check whether exploit requests reached PHP before the server was patched. Default access logs record the User-Agent but not the multipart boundary or form fields, so they catch only requests that name the tool. On Imunify360, the Incidents list shows WAF matches by rule (77830995, 77318849, 77866818, 77236259, and later PHP2Shell rules), and the ModSecurity audit log, where enabled, may include the request headers of flagged requests. A request the WAF blocked never reached PHP. Others did: anything before the rules arrived (11:10 CEST on 21 October, or 15:18 on LiteSpeed), anything on servers with the WAF off or in log-only mode, and variants the rules don’t match. Those leave no trace in the Incidents list, so don’t wait for a hit. For every account that ran unpatched PHP, keep the logs first, run a malware scan for web shells, look for PHP files written to website folders on or after 20 October, and check for unexpected processes running as the account’s user (the web server user with mod_php). Confirm what a file is before you delete it.
General hygiene, beyond PHP2Shell: run composer audit on Composer-based applications, because a PHP security audit of the interpreter says nothing about the libraries above it.
| Indicator | Value |
|---|---|
| User-Agent | Starts with php2shell- (for example php2shell-109618, php2shell-scan/109618); some security checkers use it too |
| Multipart boundary | B7kQpoc618, B7kQpoc619; renamed boundaries containing php2shell or nphp618; boundaries starting p2s, or lfi plus 16 hex characters |
| Request shape | Multipart POST with a PHP_SESSION_UPLOAD_PROGRESS field, a session ID, a file, and text fields holding binary data, usually with no Referer |
The Internet doesn’t run only PHP 8.xx
Back to the ops lead at the hosting provider reading PHP’s notice on Tuesday night.
By Friday, every branch on those servers had a fixed package, and the four php.net still-supported versions carried version numbers a scanner could read.
The next deadline is 31 December, when 8.2 leaves the supported list.
Check your accounts’ branches against the lifecycle table. For anything past end of life, the patched build is HardenedPHP on CloudLinux and Imunify360, or ELS for PHP everywhere else.
FAQ
Is it safe to run PHP 7.4 in 2026?
Not on a stock build. PHP 7.4 reached end of life in November 2022, and for PHP2Shell, php.net shipped only a source backport. Run it on a patched build, such as HardenedPHP or ELS for PHP, while the upgrade is planned.
Who provides security patches for PHP after end of life?
Distributions patch the PHP versions they ship, and vendors that own a branch patch the rest. CloudLinux covers 16 branches, 5.2 to 8.5: HardenedPHP on CloudLinux and Imunify360, ELS for PHP elsewhere.
Does disable_functions or open_basedir protect against PHP2Shell?
No. Both act on running scripts, and PHP2Shell triggers while PHP is still reading the request. Turning off session upload progress narrows one path; only a patched build closes both CVEs.
How do I run a PHP security test on my server?
For PHP2Shell: check each PHP version’s changelog or version number against the fixed list, restart PHP, confirm the WAF ruleset is 8.88 or later, and check WAF incidents and access logs for the tool’s indicators. For applications, run composer audit on their dependencies.
What is the difference between HardenedPHP and ELS for PHP?
Same technology, different packaging. HardenedPHP comes included with CloudLinux and Imunify360. ELS for PHP is the standalone product for other distributions and servers without Imunify360, on 20 platforms including Ubuntu, Debian, Alpine, and Windows Server.
CLN Login
Comments