In October 2026 two critical vulnerabilities hit the PHP core. CVE-2026-109618 and CVE-2026-109619. Researchers nicknamed them PHP2Shell. The CVSS v4.0 score reached 9.2. That score sits near the top of the scale. These flaws allow remote code execution. No login is needed. No application bug is needed. The problem lives one layer below your code.
PHP2Shell is not a flaw in your application. It lives inside PHP itself. The feature at fault is called session.upload_progress. Most developers never configure it by hand. If your server runs an unpatched PHP version and accepts file uploads you may be exposed. This holds true regardless of how carefully your own code was written. Good application security practices do not block this path.
The Feature Nobody Thinks About
PHP has tracked file upload progress for a long time. A hidden form field makes this work. Its name is PHP_SESSION_UPLOAD_PROGRESS. When a file upload includes this field PHP builds an internal tracking structure. That structure records how much of the file has arrived so far. Progress bars rely on this data behind the scenes.
Many PHP distributions enable this feature by default. An application never needs to use it directly. The underlying code path stays active anyway. This is the trap. Developers assume unused features carry no risk. PHP2Shell shows that assumption can fail.
Where the Flaw Actually Lives
Researchers at WatchTowr and Wiz traced the root cause through PHP's internals. The core issue is a use-after-free condition. This sits in how PHP manages memory across requests inside one worker process.
Here is the rough sequence of events. A worker process handles a request containing the upload-progress field. This worker could be php-fpm. It could be php-cgi. It could be mod_php running inside Apache. Under specific conditions the memory behind that tracking structure gets freed. PHP's internal engine keeps a stale reference to it anyway. Nobody clears that pointer properly.
A later request arrives at that same worker. PHP then acts on the freed memory region. By this point something else may occupy that space. Memory allocators tend to reuse freed blocks quickly. An attacker can shape what fills that space through a carefully timed follow-up request. The original structure held internal engine data. Some of that data included function pointers. Controlling the new contents of that memory can redirect program execution. This redirection can reach functions capable of running arbitrary system commands.
CVE-2026-109619 works through a related but distinct path. It involves stale global state rather than literal freed-memory reuse. The practical outcome still matches the first flaw closely. Both lead to unauthenticated remote code execution on the server.
Why "Pre-Auth" Changes Everything
No login is required to trigger this. No vulnerable plugin is required either. No mistake in your application logic plays a role. An ordinary file upload can trigger the whole chain. A contact form qualifies. An avatar uploader qualifies. A resume submission box qualifies too. Any endpoint accepting multipart/form-data becomes a potential entry point.
The vulnerable code runs inside PHP's own request-handling layer. Your application logic never even gets a turn to run. This is what separates PHP2Shell from a typical web app vulnerability. A typical flaw might need a missing authentication check or a broken access control rule. PHP2Shell needs none of that scaffolding.
This is also why people keep comparing PHP2Shell to Log4Shell. The flaw sits in shared infrastructure. Countless unrelated applications sit on top of that infrastructure without knowing it. A marketing site and a banking portal can share the same exposure if both run vulnerable PHP.
What Actually Makes a Given Server Exposed
Four conditions have to line up together to create real exposure.
An unpatched PHP version. Reports indicate affected versions span PHP 5.x through 8.x. Fixed releases do exist. These are PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12. End-of-life branches will not receive an official patch at all. PHP 5.x, 7.x, 8.0 and 8.1 fall into that bucket. Servers on these branches stay exposed unless teams upgrade to a supported branch entirely.
session.upload_progress left enabled. Many installs ship this setting on by default. An application never needs to use the feature at all. It only needs to leave the switch untouched. Most teams never audit this setting because it feels irrelevant to their work.
Any file-upload-capable endpoint. Nearly every real application has at least one of these. Contact forms, document portals and media uploaders all qualify. This condition is almost always met somewhere in a modern web stack.
A persistent worker model. This widens the window for exploitation. Apache setups using mod_php carry the highest documented risk. Worker processes there live across many requests in sequence. php-fpm deployments recycle their workers more aggressively by comparison. The exploitation window narrows under php-fpm as a result. It does not close completely though.
How This Plays Out Across Different Stacks
Not every PHP deployment carries equal risk. Shared hosting environments often run older PHP versions for compatibility reasons. These environments become prime targets. Containerized microservices running php-fpm behind a reverse proxy fare somewhat better. Short-lived worker processes reduce the exploitation window there.
Legacy enterprise applications pose their own challenge. Many run on PHP versions nobody dares to touch. Business logic was often written against quirks specific to old PHP behavior. Upgrading risks breaking functionality nobody fully understands anymore. This creates a dangerous standoff between stability and security.
Content management systems deserve special mention here. WordPress, Drupal and Joomla all sit on PHP underneath their plugin ecosystems. A site owner can patch every plugin perfectly. The underlying PHP runtime can still carry this flaw regardless. Plugin security and runtime security are separate problems entirely.
Detecting Exploitation Attempts
Exploitation tends to leave behavioral traces behind. PHP worker processes should rarely spawn child processes under normal operation. PHP2Shell exploitation often results in exactly that. Watch for php-fpm spawning unfamiliar binaries. Watch for php-cgi doing the same thing. Watch for httpd or apache2 launching shells unexpectedly.
Security researchers Florian Roth and the team behind process-watcher have published guidance here. Huntress has published monitoring recommendations as well. These indicators offer a practical detection layer. They work even before a full patch rollout completes across an environment.
What Defenders Should Actually Do
Patch first and patch fast. Upgrade to whichever fixed version matches your current branch. This remains the only complete fix available. Nothing else fully closes the vulnerable code path.
Inventory your PHP footprint aggressively. PHP hides in places teams tend to forget about. CMS platforms count. Internal admin tools count. Vendor-supplied appliances count too. Legacy services nobody has touched in years count as well. Sonatype frames this challenge as an ownership problem as much as a patching problem.
Disable the vulnerable feature if immediate patching isn't possible. Set session.upload_progress.enabled to 0 in your configuration. This removes the vulnerable code path as a temporary stopgap measure. It should never replace a real patch though.
Monitor for the child process indicators described above. Build alerting around unexpected subprocess creation from PHP workers. This buys defenders valuable time during a chaotic patch cycle.
Take high-risk systems offline when remediation will lag significantly. Several advisories recommend this step for unpatched internet-facing systems. Treat this as a last resort rather than a first response.
The Bigger Picture
Application security extends well beyond the code a team writes directly. The runtime sitting underneath that code matters just as much. A perfectly clean codebase can still fall to a single unauthenticated request. The root cause in that scenario sits inside an unpatched default PHP install. Nothing in the application layer could have stopped it.
Patch management rarely gets much attention or praise. PHP2Shell shows exactly why that unglamorous work matters so much. Inventory, ownership and timely patching form the real defense here. Everything else is secondary once those basics are in place.
Elliot
