Last revised 22 October 2026. We will update this post as vendor packages and exploitation reports develop.
What is PHP2Shell, in plain English
When a visitor loads a page, a PHP "worker" process builds it and sends it back. On a busy server that worker does not shut down afterwards. It cleans up and takes the next request.
PHP2Shell is a problem in that clean-up. If a request is cut off at exactly the wrong moment, because it runs out of memory or hits a fatal error, PHP can leave behind internal notes that point at memory it has already given away. The next request handled by the same worker may trust those stale notes. An attacker who can trigger the error on purpose, and then shape what lands in the freed memory, can make the worker run their code or hand over a copy of whatever was in that memory.
Think of a hotel housekeeping trolley. Each guest's paperwork is supposed to be cleared before the next guest checks in. PHP2Shell is a fire alarm going off mid-cleaning, so the previous guest's room key is still on the trolley when the next guest arrives. Someone who knows how to set off that alarm at the right moment can collect keys that were never meant for them.
The PHP project rated both CVEs 9.2 on CVSS v4.0. A figure of 10.0 leaked on 20 October, and the PHP Foundation has confirmed it was wrong.
Why this is different from a normal WordPress security alert
Most security notices are about a plugin, a theme or a CMS version. You update that component and the risk is gone. PHP2Shell does not work that way.
These bugs live in the PHP engine, underneath every application. Wiz, one of the research teams that reported the flaws, demonstrated unauthenticated code execution against fully updated container images of WordPress, Drupal and Joomla. Sansec reports the same against Magento 2.4.9 and ten other PHP applications. The application code was never the problem, so updating the application does not help. Only updating PHP does.
Two consequences for a business owner:
- "My WordPress is fully updated" is not a defence here.
- The person who can fix this is whoever controls the PHP version on the server: you (on a VPS), your hosting provider (on shared hosting), or the team that manages the server for you.
Who is affected
Versions
| PHP branch | Status | Fixed version |
|---|---|---|
| 8.5 | Supported | 8.5.12 |
| 8.4 | Supported | 8.4.27 |
| 8.3 | Supported | 8.3.36 |
| 8.2 | Supported until 31 Dec 2026 | 8.2.35 |
| 8.1, 8.0, 7.4 | End of life | No official release. Source backports from the PHP security team, plus vendor packages (cPanel, Plesk, CloudLinux, Ubuntu, Debian, Red Hat) |
| 7.3 and older | End of life | Vendor-dependent (CloudLinux alt-php and Ubuntu Pro cover some); otherwise upgrade |
Handler and server setup
The PHP project lists PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed as affected. Risk is not equal across them.
| How PHP runs | Risk | Why |
|---|---|---|
| Apache with mod_php | Highest | The PHP team confirmed a working exploit where one unauthenticated request triggers the bug before any application code runs. |
| PHP-FPM (Nginx or Apache) | High | Code execution confirmed through application-level code paths. Red Hat notes that FPM workers normally exit on early initialisation failures, so reliable exploitation is harder and usually needs non-default behaviour. |
| LiteSpeed / OpenLiteSpeed (lsphp) | Affected | Listed as affected by the PHP project. No LiteSpeed-specific advisory found at the time of writing. Treat lsphp as vulnerable until updated and verified. |
| php-cgi, FrankenPHP | Affected | Same engine, same bugs. FrankenPHP has shipped fixed images. |
| PHP CLI only (cron, scripts) | Low | Triggered by web requests. Update anyway so CLI and web builds match. |
Hosting type
| Hosting type | Who patches | What you do |
|---|---|---|
| Shared hosting (cPanel, Plesk, DirectAdmin) | The host | Confirm the vendor packages are applied. Use the ticket template below. |
| Managed WordPress / managed cloud | The provider | Check their status page. GoDaddy, for example, says its managed WordPress tier is patched. |
| VPS or dedicated with a control panel | You or your sysadmin | Run the panel update, restart workers, verify. |
| Self-managed Linux, Docker, Kubernetes | You or your DevOps team | Update packages or rebuild images, redeploy, verify. |
Technical deep dive for developers
This section explains the mechanisms at the level the official advisories and researcher write-ups disclose. It stops short of exploitation detail.
The root cause
All four bugs share one root cause: PHP's handling of fatal errors, and out-of-memory errors in particular, during request start-up and shutdown. When a request dies this way the per-request heap is torn down, but some engine globals still hold pointers into it. Nothing resets those globals until the normal request initialisation path runs, and parts of the next request are processed before that happens. The result is a cross-request use-after-free: request B reuses memory that belonged to request A.
The PHP project's descriptions match. CVE-2026-109618 is "RCE via OOM corruption": memory exhaustion interrupts PHP while internal request data is only partly initialised, and clean-up then treats the invalid data as valid. CVE-2026-109619 is "RCE via stale global state": request-owned state survives after its memory is freed, and a later request on the same worker uses it before initialisation resets it.
The four bug classes
Wiz groups the issues into four bugs across the two CVEs.
1. Upload-progress deserialiser use-after-free (CVE-2026-109618). The session.upload_progress feature records upload progress in a global while the multipart body is still being parsed. If memory runs out during that parse, the global is left pointing at destroyed heap. The next request on the same worker can treat attacker-controlled heap contents as live bookkeeping state. This is the path most exploit attempts use, which is why the interim WAF guidance centres on PHP_SESSION_UPLOAD_PROGRESS.
2. Remote process-memory disclosure (CVE-2026-109618). Multipart bodies are parsed before module initialisation finishes. An out-of-memory error there can leave a session-ID pointer dangling. On a later multipart request, PHP URL-encodes whatever now sits in that reclaimed memory straight into the PHPSESSID response cookie. The application never needs to call session_start(). Worker memory can hold database passwords, API keys, session tokens and configuration values from other requests, which is why secrets rotation is part of the clean-up.
3. Fatal-error backtrace use-after-free (CVE-2026-109619). PHP 8.5 can record a backtrace for the last fatal error. That global is not cleared after an out-of-memory failure, and early diagnostics in the next request can touch the freed memory. The fatal_error_backtraces=0 mitigation blocks this path, which is why it only applies to 8.5.
4. OPcache shared-memory type confusion (CVE-2026-109619). OPcache keeps a process-local slot counter and shared-memory metadata, and the counter advances before the shared state is updated. If an allocation fails in between, the shared metadata points at slots that are later reused. Because OPcache memory is shared across workers, this becomes a cross-worker type confusion. Wiz demonstrated code execution against WordPress through this path.
Why mod_php is worse than FPM
Under mod_php the PHP engine lives inside the Apache worker and keeps serving requests after a failure, so the stale state is simply there for the next request. Under PHP-FPM, Red Hat reports that a worker which fails during early initialisation normally exits before reaching the corrupted structures, so the attacker needs the application to parse a second request body during script execution, or another non-default behaviour. That is a higher bar, not a safe harbour: the PHP team confirmed FPM code execution through application paths.
Why configuration changes are not a fix
The confirmed session paths can be blocked with session.upload_progress.enabled=0, and the backtrace path with fatal_error_backtraces=0 on 8.5. The PHP advisory states these block "the confirmed session paths but not other variants," and Wiz expects more variants. The patched releases fix the root cause (stale state surviving a fatal error), which the settings do not.
Am I vulnerable? A 2-minute self-check
No server access needed.
- WordPress: go to Tools, then Site Health, then the Info tab, then Server. Compare the PHP version shown with the fixed-version table. If it is 8.1.x or lower you are on an end-of-life branch and need to talk to your host.
- Hosting panel: in cPanel look for "Select PHP Version" or "MultiPHP Manager"; in Plesk open the domain's "PHP Settings".
- Ask your host. On shared hosting the version number alone may not tell you whether the backported fix is installed, because cPanel and Plesk kept the same version string for 7.4, 8.0 and 8.1. Ask directly whether the fix for CVE-2026-109618 and CVE-2026-109619 is applied, and when.
- If you are not sure, assume you are exposed and move to the fix section, or contact someone who can check for you.
How to fix it, by environment
Two rules apply everywhere. Update PHP. Then restart every PHP worker (Apache, PHP-FPM, LiteSpeed, long-running queue workers). A patched package with the old binary still in memory protects nothing.
cPanel / WHM (EasyApache 4)
cPanel shipped fixed ea-php82 through ea-php85 (8.2.35, 8.3.36, 8.4.27, 8.5.12) and backported both CVEs into ea-php74, ea-php80 and ea-php81 with the version number unchanged. Run EasyApache 4 updates in WHM, or from the shell:
yum clean all
yum update "ea-php*"
/scripts/restartsrv_httpd
/scripts/restartsrv_apache_php_fpm
Because the 7.4, 8.0 and 8.1 packages keep their old version numbers, verify through the changelog rather than php -v:
rpm -q ea-php81-php-cli --changelog | grep -E 'CVE-2026-(109618|109619)'
No output means the fix is not installed yet. Update cPanel & WHM itself too: its internal PHP was fixed in 138.0.18, 136.0.50, 134.0.66 and 110.0.153.
Plesk
Plesk released fixed PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 for Linux and Windows. For PHP 7.4.33, 8.0.30 and 8.1.34 on Linux the version number did not change: builds dated 21 October 2026 or later carry the fix. Update through Tools & Settings, then Updates, then confirm the build date:
/opt/plesk/php/8.1/bin/php -v
Plesk's own engine (sw-engine) was also vulnerable and is fixed in Obsidian 18.0.81 Update 4 and 18.0.80 Update 11. Apply that too, then restart PHP-FPM or Apache.
CloudLinux alt-php, ea-php on CloudLinux, and LiteSpeed
CloudLinux has pushed fixed alt-php packages for every version it maintains (5.2 through 8.5) to its stable repositories, and fixed ea-php52 through ea-php85 for cPanel on CloudLinux. A normal update picks them up:
# CloudLinux 7
yum clean all && yum update 'alt-php*' 'ea-php*'
# CloudLinux 8, 9, 10
dnf clean all && dnf upgrade 'alt-php*' 'ea-php*'
Verify with the changelog, since these packages keep lower version numbers than upstream:
rpm -q --changelog alt-php82-common | grep -E 'CVE-2026-(109618|109619)'
If you run Imunify360, confirm the ModSecurity ruleset is 8.85 or later. Ruleset 8.83 ran only on Apache and Nginx; 8.84 and later also run on LiteSpeed. The ruleset is a virtual patch for the upload-progress path and does not cover the out-of-memory path.
For LiteSpeed Enterprise and OpenLiteSpeed, update the lsphp8x packages from your repository, restart LiteSpeed, and confirm with the binary (for example /usr/local/lsws/lsphp84/bin/php -v). We could not find a LiteSpeed-specific advisory at the time of writing; if your lsphp build still shows a pre-fix version, raise it with LiteSpeed or your host.
Ubuntu, Debian and the RHEL family
Distribution packages carry backported fixes under their existing version numbers, so compare the full package version string, not the upstream number.
| Distribution | Package | Fixed version | Advisory |
|---|---|---|---|
| Ubuntu 26.10 | php8.5 | 8.5.9-0ubuntu2.1 | USN-8948 |
| Ubuntu 26.04 LTS | php8.5 | 8.5.4-0ubuntu1.5 | USN-8948 |
| Ubuntu 24.04 LTS | php8.3 | 8.3.6-0ubuntu0.24.04.13 | USN-8948 |
| Ubuntu 22.04 LTS | php8.1 | 8.1.2-1ubuntu2.28 | USN-8948 |
| Ubuntu 20.04 and older | php7.4 and earlier | Ubuntu Pro (ESM) only | USN-8948 |
| Debian 13 (trixie) | php8.4 | 8.4.27-1~deb13u1 | DSA-6574-1 |
| Debian 12 (bookworm) | php8.2 | 8.2.35-1~deb12u1 | DLA-4848-1 |
| RHEL 8 / 9 / 10 and clones | php, php:8.x modules | Per-stream errata in Red Hat bulletin RHSB-2026-013 | RHSB-2026-013 |
# Debian / Ubuntu
sudo apt update && sudo apt install --only-upgrade 'php8.*'
sudo systemctl restart php8.3-fpm apache2 # adjust to your version and stack
# RHEL family
sudo dnf update 'php*'
sudo systemctl restart php-fpm httpd
Then confirm with dpkg -l 'php8*' or rpm -q php that the installed version matches the table.
Docker and container images
Official PHP images have fixed tags for every supported branch, for example php:8.4.27-fpm, php:8.3.36-apache and php:8.2.35-cli. FrankenPHP images are fixed as well. There are no fixed tags for 8.1 or older. Rebuild on the new base, redeploy, and replace every running container. The PHP version is baked into the image tag, so host-level patching does not cover containers.
Shared hosting: what to ask your host
Copy this into a support ticket:
Subject: PHP2Shell patch status (CVE-2026-109618 / CVE-2026-109619) for my account
My account runs PHP [version] on [domain]. Please confirm: (1) whether the vendor fix for CVE-2026-109618 and CVE-2026-109619 has been applied to the server hosting my account, and when; (2) whether PHP-FPM / Apache workers were restarted after the update; (3) if my PHP branch is 8.1 or older, whether the backported package is installed, and which supported branch you recommend I move to; (4) if the patch is not yet applied, which interim mitigations are in place (WAF rule, session.upload_progress disabled) and your ETA.
If the answer is vague, or the ETA is more than a day away, escalate or get help moving to a host that has patched.
If you cannot patch today
These settings reduce exposure. The PHP project states that only an update is a complete solution. All of them must be set in php.ini, an FPM pool file (php_admin_value) or the web server configuration, with every worker restarted afterwards. Setting them through .user.ini, .htaccess php_value or ini_set() does not work, because the vulnerable code runs before those are read.
; CVE-2026-109619: blocks the confirmed session upload-progress path only
session.upload_progress.enabled = 0
; CVE-2026-109619, PHP 8.5 only: blocks the confirmed fatal-backtrace path only
fatal_error_backtraces = 0
; CVE-2026-109618: removes the memory_limit trigger, with real trade-offs
memory_limit = -1
post_max_size = 8M ; or 32M if uploads are required
upload_max_filesize = 2M ; must stay below post_max_size
What each one costs you:
- session.upload_progress.enabled=0 disables upload progress bars that depend on it. Most modern applications do not use it.
- memory_limit=-1 removes PHP's own memory ceiling. Replace it with a container or cgroup limit that kills only the affected worker, and watch memory use. The PHP project warns against
RLIMIT_ASorRLIMIT_DATAfor this. - A low post_max_size breaks large uploads. The PHP project also recommends request-size, field-count and multipart-part limits at the web server or proxy, applied even when there is no usable
Content-Lengthheader. - WAF rules from Cloudflare, Imunify360 and others block the request shapes seen so far. Attackers have already been observed changing payloads to get past them, and Datadog's refined exploit returned HTTP 200 and left the worker running. A WAF buys hours, not a fix.
Two further points from the advisory: hiding diagnostics with error_reporting, display_errors or @ does not help, and you should remove invalid or deprecated per-request INI settings that emit warnings before initialisation, since those warnings are part of the attack surface for CVE-2026-109619.
If you cannot patch today and the site is public, emergency website recovery is the route for getting it patched and checked without waiting on a host.
EOL PHP (7.x, 8.0, 8.1): no official fix, and what to do
PHP 8.1 and older stopped receiving releases before these bugs were reported, so there is no 8.1.x, 8.0.x or 7.4.x release with the fix. Three routes:
- Vendor packages. cPanel, Plesk, CloudLinux, Ubuntu (22.04 for 8.1; Pro ESM for older), Debian LTS and Red Hat received the patches in advance and have shipped or are shipping backported packages. Apply the package and verify through the changelog or build date as shown above.
- Source backports. The PHP security team published minimal backport branches for 7.4, 8.0 and 8.1 on GitHub for people who compile PHP themselves and have no LTS vendor. These are not full releases and carry no other fixes.
- Upgrade. This is the real answer. PHP 8.2 leaves support on 31 December 2026, so a move straight to 8.3 or 8.4 avoids doing this twice. For WordPress the jump from 7.4 to 8.3 is usually a matter of testing plugins on a staging copy; custom applications may need code changes. Either way, the server should run a supported PHP by the end of this year.
One caution: the community-maintained Remi repository, which many RHEL-family servers use for newer PHP, said it would not have the update on release day. If your server pulls PHP from there, check its current status or switch to distribution packages.
After patching: did anyone get in?
Patching stops future attacks. It does not undo one that already happened, and Amazon's honeypots recorded an exploitation attempt on 17 October, four days before disclosure. Start your review from that date.
Logs to inspect
- PHP error log: "Allowed memory size exhausted" fatals reporting their location as "Unknown on line 0". That location means PHP failed during request initialisation, before any script ran, which is the signature of the out-of-memory trigger.
- Apache error log: child process crashes with "exit signal Segmentation fault". Crashes are typical of failed attempts; a successful one may not crash anything.
- Access logs: POST bodies containing
PHP_SESSION_UPLOAD_PROGRESS, unusually large POSTs, repeated HTTP 500s from one client, and form-encoded POSTs with a single very long field name. - Responses: unusually large or malformed
PHPSESSIDcookies point at the memory-disclosure path. - Process activity: a web or PHP-FPM worker spawning a shell is the most direct indicator. Review any
shorbashchild ofhttpd,apache2,php-fpmorlsphp.
Webshell sweep
Search the document root and uploads directories for PHP files modified since 17 October, PHP files inside wp-content/uploads or equivalent media folders (there should be none), and files whose names mimic core files but sit in the wrong place. Compare core, plugin and theme files against clean copies. Check cron entries and systemd timers for anything new.
Rotate secrets, even if you find nothing
The memory-disclosure bug returns fragments of worker memory to a remote client and leaves no trace on disk. You cannot prove afterwards that nothing leaked. Once patched, rotate what the workers could have held:
- Database passwords (
wp-config.php,.env, application config) - Application keys and salts (WordPress salts, Laravel
APP_KEY, framework encryption keys) - Third-party API keys and tokens in configuration (payment gateways, email, integrations, cloud storage)
- Admin passwords and CMS API credentials
- TLS private keys, if they live on the same server
- Active user sessions: force a logout of all users so stolen tokens stop working
The bigger lesson
Three separate teams found these bugs within weeks of each other in August 2026, and AI tooling was part of the story on both sides. The PHP Foundation notes that Alpha-Omega scanned PHP with an AI model earlier in the year, Wiz used AI models to adapt its exploits to different PHP versions and memory layouts, and the Foundation's own view is that tools now find bugs faster for defenders and attackers alike. The CVE IDs leaked a day early, a proof-of-concept video was posted by mistake, fixed container images appeared six hours before the embargo lifted, and honeypots saw attempts within hours of release.
The takeaway is not that PHP is unsafe. It is that the window between "a patch exists" and "attackers are using the bug" is now measured in hours. A site patched within a day of every critical release is in a different risk class from one patched when someone remembers.
Need this handled today?
If you are not sure whether your site is patched, do not have server access, or your host is not responding, WebXSentry can take it from here. WebXSentry is the website maintenance service of Aarav Infotech, which has kept 1000+ sites patched and online for 15+ years, so this is routine work for us.
Emergency PHP2Shell patch and audit. A one-time engagement, no plan needed. We confirm your PHP version and handler, apply the patch or vendor package, restart workers, verify through the changelog, sweep for webshells and recent file changes, review logs from 17 October onwards, and rotate the secrets that matter. For shared-hosting customers we deal with the host on your behalf. Start with emergency website recovery, or choose "hacked, down or flagged" on the quote form.
Ongoing protection. The next engine-level bug will arrive on its own schedule. Every WebXSentry maintenance plan includes security patching, malware scanning and removal, encrypted off-site backups and uptime monitoring, with a first reply by the next business morning. Not sure what you have today? Request a free website maintenance audit.
Call +1 (855) 650-4040 in the US, WhatsApp +91 80081 00192, or use the contact page. Tell us your PHP version and hosting type and we will tell you in plain language where you stand.