4 min readdev.to
How Running Out of Memory Became a Server Takeover in PHP
PHP2Shell turns a failed memory allocation into a full takeover, with no login. The mechanism is a worker reusing leftovers from a request that already died.
"The server would have to run out of memory first." That sounds like a reason to file a bug under not urgent.
On 21 October, two bugs that start exactly that way were published as critical. Both let someone on the internet, with no account and no password, run commands on the server. Both have been in PHP since version 5.4.
They are called PHP2Shell. Wiz Research, who found them, demonstrated working attacks against WordPress, Drupal and Joomla.
How they work is worth following even if you never touch PHP, because the same shape turns up anywhere code handles one request after another.
Why running out of memory is dangerous
PHP does not start a fresh process for every visitor. It keeps a pool of workers alive, and each handles request after request. Between them, PHP throws away the memory that request used and starts clean. That cleanup is the only reason one visitor's data does not end up in the next visitor's page.
Running out of memory interrupts the cleanup halfway. The memory gets thrown away. But some of PHP's long-lived variables are still pointing at it. The request is dead; the pointers it left behind are not. Whoever lands on that worker next inherits them.
That is the whole trick, in four different places.

The same worker serves the next visitor. Source: Wiz Research, PHP2Shell.
Take the clearest one. While PHP receives an uploaded file, it records the progress in the session. Make it run out of memory right there, and the pointer to the session ID is left aimed at memory that has already been freed.
Freed memory does not stay empty. The attacker sends more requests to refill it with bytes of their choosing, then sends one more upload. The worker follows that old pointer, reads whatever sits there now, and writes it into the session cookie it sends back.
You make a request. The server replies with a piece of its own memory, in a cookie. Wiz notes this works even on sites that never start a session.

Server memory, handed back in a cookie. Source: Wiz Research, PHP2Shell.
That gets the attacker information. The same memory error leaves a second thing behind: the bookkeeping PHP uses to rebuild saved objects from text. Someone who controls the freed memory controls structures PHP still believes are real. The leak tells them where things sit; the stale bookkeeping lets them corrupt it. Together: code execution, no login.
The second CVE is the same idea in two more spots. PHP keeps a pointer to the last crash report and forgets to clear it, so the next request that prints a warning follows it somewhere it should not. And in OPcache, the shared cache of compiled scripts, a failed allocation can leave one worker handing another a pointer to the wrong kind of object — inside memory every worker shares.
The part that should bother you
A PHP core developer saw the first signs of this in 2024, during an earlier security audit, and could not turn it into a working attack. A fair call at the time.
Then in August 2026, three separate parties reported the same underlying bug within two weeks: Calif, OpenAI and Wiz. Wiz credits AI models for making the work practical, though that is its own account, not a measurement anyone else checked.
The PHP Foundation's write-up is more useful. Its security team decides by consensus. That stalled the fix for months, and the Foundation calls it a "structural failure." It is switching to majority votes. It has also published 15 CVEs since 1 July while sorting through more than 100 invalid or duplicate reports.
What to do
- Update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35. If someone else hosts your PHP, check they have. Sansec published stopgap mitigations, including blocking file uploads at the web server, if you cannot update today.
- Then look at your own code that outlives a single request: thread pools, reused serverless containers, anything pooled. When a request dies halfway through, what does it leave behind? Same bug, different language.
- Stop treating "nobody has exploited it yet" as a severity input. It measures how much effort was available the day someone triaged it. That number has moved.
Where this breaks down
These attacks need things to line up: a way to force the memory error, the right configuration, and the right timing to win the race for freed memory. "Decades old and exploitable today" is true. "Trivially exploitable everywhere" is not, and I have not seen a public exploit.
Takeaway
Error paths are code too. Just the code nobody profiles, nobody fuzzes hard, and nobody reads twice.
Which error path in your system have you never actually watched run?
Sources
- The PHP Foundation: today's security release and how we're strengthening PHP security — 21 Oct 2026
- Wiz Research: PHP2Shell — Oct 2026
- Sansec: PHP2Shell research notes and mitigations — 21 Oct 2026