Skip to main content
Blog|
Latest news

PHP2Shell: what CVE-2026-109618 and CVE-2026-109619 do, and how we patched every server

|
Oct 21, 2026|10 min read
LATEST NEWSPHP2Shell: whatCVE-2026-109618 andCVE-2026-109619 do, and how wepatched every serverHOSTNEY™hostney.comOctober 21, 2026

Short answer: On October 21, 2026, PHP released 8.2.35, 8.3.36, 8.4.27 and 8.5.12 to fix two critical vulnerabilities nicknamed PHP2Shell. Both give an attacker a path to running code through PHP itself, with a crafted request that is processed before WordPress or any other application code starts, so no plugin or application firewall can stop them. Every PHP version that serves websites on Hostney now runs the fixed release, and because our PHP runs from container images built from PHP’s own releases, the update did not have to wait for operating system packages. While the fix was on its way, Hostney blocked the request type the published attacks use on every site and switched off the two PHP features the second bug relies on. PHP 8.1 and older will not get a fix.

What happened#

On October 20, the PHP security team announced an emergency release for two vulnerabilities, each rated 9.2 on the CVSS v4.0 scale, after details from the embargoed reports leaked. The fixed versions were scheduled for October 21 at 14:00 UTC. By that morning, Cloudflare was reporting early attack attempts and had shipped firewall rules for its customers. PHP released on schedule.

Only supported branches got new versions. PHP 8.1 reached end of life at the end of 2025, and nothing older has been maintained for years, so there is no official fix for any of them. Sansec, the security firm that tracked the disclosure, reports that the bugs affect PHP versions going back to 5.4.

What the two bugs do#

Most PHP vulnerabilities you read about live in a plugin, a theme or a framework, and updating that component closes them. These two live in PHP’s own request handling, in code that runs for every request to every PHP site before the site’s own code gets control. A WordPress blog, a Magento store and a hand-written PHP script are exposed the same way.

CVE-2026-109618: running out of memory at the wrong moment#

When a request uses more memory than PHP allows, PHP aborts it. Site owners usually meet this as the allowed memory size exhausted error. The bug is in what happens if that abort lands while PHP is still building the request’s internal data: part of the data is already reachable but not yet filled in, and the cleanup code that runs afterwards treats it as valid. An attacker who controls the shape of the request can turn that into memory corruption and then code execution.

Every trigger in PHP’s advisory is an upload request, the multipart/form-data format a browser uses when a form sends a file. A body with no usable declared length, a part with an unlimited number of headers, empty file fields, and deeply nested field names all make PHP allocate memory while it parses the body. PHP parses that body before any application code runs. The advisory also notes that the same out-of-memory condition can be reached in application-specific ways, through any input that makes a script allocate a lot.

PHP’s researchers demonstrated the attack over HTTP against Apache with mod_php, using default PHP settings. For PHP-FPM, which most hosts run, the published analysis stops short of a working exploit: FPM ends the worker process when request startup fails, which gets in the way of the demonstrated technique. Not demonstrated is not the same as not affected, and the fixed releases close it for every setup.

CVE-2026-109619: one request's leftovers reach the next one#

PHP-FPM and mod_php keep worker processes alive and reuse each one for many requests (what PHP-FPM is and how it works covers the model). This bug lets data that belonged to one request stay attached to the worker after its memory was freed. A later request handled by the same worker can use that stale data before PHP resets it, and a crafted pair of requests turns that into code execution.

PHP confirmed two ways to leave that stale data behind:

  • Session upload progress. An upload interrupted at the right point leaves session data in the worker, and a later upload-progress check picks it up. PHP validated this path against PHP-FPM.
  • Fatal error backtraces, a feature new in PHP 8.5. A fatal error with backtraces turned on leaves the backtrace in the worker, and a later diagnostic message uses it. PHP confirmed this one on mod_php.

A third path goes through PHP settings applied per request, which only exists where the web server passes them in: php_value lines in .htaccess under mod_php, or a front end sending PHP_VALUE to PHP-FPM.

Why a WordPress security plugin cannot help#

A security plugin is PHP code, and it runs after PHP has parsed the request. By the time Wordfence, a login limiter or a hardening plugin gets control, the parsing these attacks target is already done. This is the situation server-level security exists for: the defense has to sit in front of PHP, or be a fix inside PHP itself.

Which versions are fixed#

PHP branchFixed inStatus
8.58.5.12Fixed
8.48.4.27Fixed
8.38.3.36Fixed
8.28.2.35Fixed
8.1 and oldernoneEnd of life, no fix

Any release from those versions onward includes the fixes. If a site still runs 8.1 or an older branch, PHP2Shell is one more reason to move it: every end-of-life PHP version already carries known critical vulnerabilities that will never be fixed, as we covered in the risks of running end-of-life PHP.

What we did on Hostney#

Before the fix was released#

As soon as the details were public, we put temporary protections in place on every server.

Upload requests stopped in front of PHP. Our web servers refused every multipart/form-data request before it could reach PHP, on every site. Both published attacks need that request type, and refusing it at the web server means PHP never parses the body at all. We put the check at every point where a request is handed to PHP, so no route to PHP skipped it. The price was that file uploads and some forms did not work for a few hours: the media library, plugin and theme uploads, forms with an attachment, and a few settings screens that save their data the same way. We posted a notice in the control panel so nobody had to guess why.

Two PHP features switched off. Session upload progress is the feature the second bug uses on PHP-FPM, and fatal error backtraces are the PHP 8.5 feature behind its confirmed exploit. We turned off session upload progress on every PHP version and fatal error backtraces on PHP 8.5. Both are set at the server level, where a site’s own php.ini or .user.ini cannot switch them back on. PHP advises keeping upload progress off even after patching, so both stay off. Very little depends on either one. An upload progress bar built on PHP sessions stops reporting, and PHP 8.5 error logs no longer add a backtrace under a fatal error, while the error line itself is still logged.

We also checked a quick fix that circulated early, setting file_uploads = Off , and it does not stop the attack. We sent an upload to a test server with that setting: PHP still parsed the entire upload request and passed its form fields to the script. The only difference was that it skipped saving the file, and the parsing is where both bugs live.

The fix, without waiting for the operating system#

On most Linux servers, PHP is an operating system package. A fix reaches it when the distribution, or the third-party repository the PHP came from, rebuilds that package: Red Hat publishes an advisory, AlmaLinux and Rocky Linux rebuild it, and only then does an update show up on the server. That chain often takes days. When PHP released this fix, Red Hat had not published an advisory for it yet, and the Remi repository, where many Red Hat based servers get newer PHP versions, had announced it would not have updates that day.

PHP on Hostney does not come from the operating system. Every PHP version we offer runs in containers built from PHP’s own source releases, so the operating system underneath, and when it gets patched, has no say in which PHP a site runs. When the official builds of 8.2.35, 8.3.36, 8.4.27 and 8.5.12 were published, we rebuilt the image for every version we offer and rolled it out to every server.

Every PHP worker was restarted in the process. The second bug lives in long-running workers, so a fresh start counts as much as the new binary. Once every site was on a fixed release, we lifted the upload block.

Sites still on PHP 8.1 or older#

Those versions will never be fixed, so for any site still running one, the upload block stays in place. The way out is to switch the site to PHP 8.2 or newer. The PHP manager in the control panel now says it plainly whenever an end-of-life version is picked: every end-of-life version has known critical security vulnerabilities that will never be fixed.

What kept the risk contained#

Each account on Hostney runs PHP in its own containers, as that account’s system user, with access to its own files and nothing else (how we isolate websites with containers explains the setup). A code-execution bug in PHP is serious on any platform. On ours, it starts inside one account’s container, not on a shared server where every customer’s files are in reach.

What you should do#

If your sites are on Hostney#

Nothing, unless a site still runs PHP 8.1 or older. In that case, open the site’s PHP manager in the control panel and switch it to 8.2 or newer. If you are worried about compatibility, the end-of-life PHP guide walks through testing an upgrade before you make it.

If you host somewhere else#

First, find out which PHP version each site runs. How to check your PHP version covers the command line and phpinfo() , and in WordPress the same information is under Tools > Site Health > Info > Server.

Then update to 8.2.35, 8.3.36, 8.4.27, 8.5.12 or later, and restart PHP-FPM or Apache so no worker keeps running the old code. If PHP comes from your Linux distribution, the version number may not change: Debian, Ubuntu and Red Hat backport fixes into their own packages, so check your distribution’s security tracker for these two CVEs. If your PHP comes from the Remi repository on a Red Hat based system, note that it announced it would not have updates on release day.

If you cannot update right away, refuse upload requests before they reach PHP. This breaks file uploads, so remove it once you have patched. In nginx, inside every location that passes requests to PHP:

if ($http_content_type ~* "multipart/form-data") {
    return 403;
}

In Apache, or in an .htaccess file above any existing rewrite rules:

RewriteEngine On
RewriteCond %{HTTP:Content-Type} multipart/form-data [NC]
RewriteRule ^ - [F]

Use $http_content_type in nginx, not $content_type . The first holds every Content-Type header a request sends, the second only the first of them, so a request carrying two could get past a check on $content_type .

Also switch off the two features the second bug uses, in php.ini or in each PHP-FPM pool, and restart every worker afterwards:

; php.ini
session.upload_progress.enabled = 0
fatal_error_backtraces = 0      ; PHP 8.5 and newer only

; or in a PHP-FPM pool, where a site cannot override it
php_admin_flag[session.upload_progress.enabled] = off
php_admin_flag[fatal_error_backtraces] = off    ; PHP 8.5 and newer only

None of this replaces the update. PHP’s own advisory says the patched release is the only complete fix.

If you think a site was attacked#

Look for files you did not upload, admin users you did not create, and outgoing traffic you cannot explain, especially from the hours between the leak and your update. What to do if your WordPress site was hacked covers the cleanup step by step.

Summary#

PHP2Shell is two bugs in PHP’s own request handling: CVE-2026-109618 corrupts memory when a request runs out of memory at the wrong moment, and CVE-2026-109619 lets one request’s leftovers reach the next request on the same worker. Both are reachable before any application code runs, so updating PHP is the fix and plugins cannot stand in for it. Hostney blocked upload requests in front of PHP and switched off the two features the second bug uses while the fix was on its way, then rolled out 8.2.35, 8.3.36, 8.4.27 and 8.5.12 to every server and restarted every PHP worker, without waiting for operating system packages, because our PHP runs from containers built from PHP’s own releases. If any of your sites still runs PHP 8.1 or older, move it to a supported version: those branches will not be fixed.