PHP maintainer bukka published two critical advisories on php-src on October 21, 2026, alongside PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Security researchers named the pair PHP2Shell. Both bugs let an unauthenticated attacker run code on your server as the account your PHP workers use, and both score 9.2 on CVSS v4. The PHP team lists configuration changes that shrink the risk, and says in both advisories that upgrading is the fix you can count on.
The two advisories
| Advisory | CVE | Bug | CVSS v4 | Fixed in |
|---|---|---|---|---|
| GHSA-w8hw-w9fx-j79w | CVE-2026-109618 | RCE via out-of-memory corruption | 9.2 | 8.2.35, 8.3.36, 8.4.27, 8.5.12 |
| GHSA-6wmf-4rv5-p3rp | CVE-2026-109619 | RCE via stale global state | 9.2 | 8.2.35, 8.3.36, 8.4.27, 8.5.12 |
The vector for both reads AV:N/AC:H/AT:P/PR:N/UI:N: network access, no login, no user interaction. The high complexity and "attack requirements present" ratings mean an attacker needs a working heap layout and the right server setup. Four researchers reported both bugs, and the same four PHP developers wrote the fixes.
CVE-2026-109618: out of memory, mid-request
PHP has used longjmp() to abort a request when it runs out of memory. If an allocation fails while the engine has set up part of a request, shutdown can read or branch on memory in an invalid state. The advisory describes several ways to push a request into that state while staying under limits that look safe, most of them in multipart parsing:
- requests with no usable declared content length
- multipart parts with unrestricted headers
- empty file controls combined with nested field names
The PHP team validated unauthenticated RCE against Apache mod_php with default limits. mod_php runs shutdown even when startup fails, which opens the path. The advisory calls FPM susceptible in principle, with no complete FPM exploit shown, and expects FrankenPHP and LSAPI to be exposed as well.
The patch removes longjmp() from the OOM path. PHP now raises a soft OOM at the next safe point in the VM, and exits with _exit() at a higher hard threshold.
CVE-2026-109619: one request's memory, another request's crash
A PHP worker keeps some global state between requests, and part of that state can point at memory a previous request owned. Code that runs before request initialization can consume that stale pointer, which gives an attacker a use-after-free. With a crafted heap layout, the PHP team says that becomes remote code execution.
The confirmed RCE uses session upload progress as one ingredient and, on PHP 8.5, fatal error backtraces as another.
Stopgaps if you can't upgrade today
Set these in your server's php.ini, the administrative config your application code can't override, and then restart every worker. A reload that leaves old workers alive doesn't count.
; CVE-2026-109619: blocks the demonstrated producer and consumer paths
session.upload_progress.enabled = 0
; PHP 8.5: removes the producer the confirmed RCE uses
fatal_error_backtraces = 0
; CVE-2026-109618: the main config mitigation, and it is incomplete
memory_limit = -1
The memory_limit = -1 line comes with conditions. No other setting may restore a finite limit, and you trade the OOM bug for a process that can grow until the container kills it. Pair it with a cgroup or container memory cap, which the advisory calls helpful but incomplete. Avoid RLIMIT_AS and RLIMIT_DATA, since those can trigger the vulnerable longjmp() path.
At the proxy or load balancer, keep post_max_size conservative, enforce decoded body size, and cap header count, multipart parts and uploads. If your application never accepts multipart requests, block them at the front.
Upgrade
# Confirm what your workers run
php -v
php -r 'echo PHP_VERSION, PHP_EOL;'
# Docker: rebuild on the patched tag
docker pull php:8.4-fpm
docker build --pull --no-cache -t my-app .
Your distribution's PHP packages may carry the fix under a different version string. Read your vendor's security tracker for CVE-2026-109618 and CVE-2026-109619 before you assume an old version number means an unpatched build.
The advisories list patched releases for 8.2 through 8.5. If you run 8.1 or older, you get no fix from the PHP project, and the stopgaps above cover part of the surface.
This week
- Upgrade every PHP runtime to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, and restart all workers.
- If an upgrade has to wait, ship the
php.inichanges above today and block multipart at the edge for apps that don't need uploads. - Rank
mod_phpservers first. The PHP team proved the OOM exploit there. - Search your access logs for the past two weeks for oversized or malformed multipart POSTs to endpoints that never take uploads.
- Put any PHP 8.1 or older app on next sprint's board. The stopgaps don't close CVE-2026-109618.
Volodymyr Chornous

