$RodHat_
MOTD

PHP2Shell lands: two CVSS 9.2 RCEs in the multipart parser, patch now

Published by

This article may contain Amazon affiliate links. I may earn a commission if you buy through them. Disclosure.

Editorial card: PHP2Shell lands: two CVSS 9.2 RCEs in the multipart parser, patch now
Photo: RodHat / RodHat Editorial

Yesterday I told you PHP was dropping two CVSS 9.2 patches at 14:00 UTC, details embargoed. The embargo is gone. Here is what was in the box.

The nickname making the rounds is PHP2Shell. Two bugs, both in the multipart machinery, both unauthenticated, both get you a shell.

CVE-2026-109618: OOM in the multipart parser corrupts the request heap. PHP’s out-of-memory handler bails via longjmp(), which punches straight out of the allocator no matter where the code is. When that happens mid-parse, request data is only partially initialized. The shutdown path then walks over that half-dead memory. An attacker can deliberately trigger OOM through the multipart form parser, four documented paths: a body with no declared content-length, packing enough MIME headers into a single part, submitting empty file controls that bypass the upload count limit, or deeply nested field names. The result is controlled corruption of heap memory allocated for the current request. “Controlled corruption” is security-speak for “you probably get RCE if you’re patient enough.”

CVE-2026-109619: use-after-free in session.upload_progress. The php_session_rfc1867_callback function in ext/session/session.c retains global state pointing into memory owned by a request. That memory gets freed at request end. The global pointer does not. A subsequent request on the same worker reads stale state, and that stale state is attacker-influenced via the previous upload. Classic inter-request UAF. This one works under default PHP configuration, which is how most people run PHP, which is a lot of PHP.

The combined nickname exists because researchers think the two are chainable: trigger the OOM corruption to set up a heap primitive, then leverage the UAF to execute. The PHP security team has not confirmed the chain works reliably. The researchers circulating proof-of-concept code say it does on Apache with mod_php. Believe who you want. Patch either way.

Fixed versions: PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35. If you are still on 8.1 you are six months past EOL and this is the least of your problems, though the bug is likely there too.

If patching is not immediate: block multipart POST requests at the reverse proxy for any PHP application that does not genuinely need file uploads. For the session bug specifically, session.upload_progress.enabled = 0 in php.ini closes CVE-2026-109619 without a code upgrade. Restart workers after the config change.

For those running PHP behind Nginx proxying to php-fpm, the good news is that php-fpm’s per-request worker model limits the UAF window somewhat. Not to zero. Patch anyway.

The disclosure timeline on this one was messy. The CVE IDs leaked onto a public forum October 20, forcing the PHP team to advance the out-of-band release by roughly 18 hours. That kind of premature disclosure is exactly the scenario that makes responsible disclosure agreements twitchy. The researchers who found these were working with the PHP team; someone else put the CVE IDs on Hacker News. It happens. The patches were already done, which is the only part that actually matters.

Go patch. The PoC is already out there.

Sources

  1. ETR: CVE-2026-109618 and CVE-2026-109619 Critical Unauthenticated RCE in PHP (Rapid7)
  2. Critical Remote Code Execution Vulnerabilities in PHP Core (Akamai Security Research)