· via dev.to (home feed)
PHP session serializer mismatch CVE-2026-115560 can lead to remote code execution; patch pending
An unpatched PHP flaw, CVE-2026-115560, lets a session serializer mismatch push attacker-controlled data into unserialize(), with RCE possible if a gadget class exists; disabling upload progress mitigates it.

A write-up published on dev.to on 6 November explains how CVE-2026-115560, an unpatched PHP vulnerability, can turn a mismatch between session serialization handlers into remote code execution. According to the article, PHP has not yet shipped a fix — one is planned for the next regular release — and the documented mitigation is to disable the session upload progress feature. No exploitation in the wild had been reported as of the advisory, and PHP had not published an official CVSS score or an affected-version list, although some sources cite a vendor CVSS v4 score of 9.2, rated Critical.
How the mismatch happens
PHP converts $_SESSION into a string for storage using a serialize handler selected via session.serialize_handler. Three handlers exist — php (the default), php_binary and php_serialize — and the handler used to write session data must match the one used to read it back.
The two formats disagree in a dangerous way. The php handler stores each entry as a name, a pipe character, then the serialized value; when reading, it splits at the first pipe and passes everything after it to unserialize(). The php_serialize handler encodes the entire session as a single serialized array, in which pipes can legitimately appear inside string values.
The second ingredient is session upload progress, a feature enabled by default. When a multipart form contains a field named PHP_SESSION_UPLOAD_PROGRESS, PHP writes upload progress details — including the client-supplied field value and the uploaded file name — into $_SESSION while the request body is still being parsed, before any application code runs. That write uses the serializer configured in php.ini, not whatever the application later sets.
If php.ini selects php_serialize or php_binary, but the application calls ini_set('session.serialize_handler', 'php') right before session_start() — a pattern the article links to legacy compatibility — data written in one format is decoded as the other. The php reader then treats the first pipe inside attacker-controlled progress data as a delimiter and unserializes the remainder.
Three conditions must align
As summarised in the dev.to article, PHP says exploitation requires all of the following:
session.serialize_handlerset tophp_serializeorphp_binaryin configuration, so stock installs using thephpdefault fail this check- application code switching the handler back to
phpat runtime before callingsession_start() session.upload_progress.enabledon, which is the default
The article argues this combination is rare, which is why PHP is handling the fix in the regular release cycle rather than as an emergency.
Vendor write-ups cited by the article, such as SIOS Security Blog, describe the underlying problem as stale global state: the tainted data is planted in one HTTP request and misparsed in another handled by the same PHP-FPM worker. A community backport patch that resets the serializer pointer between requests fits that picture, though the article cautions that only the official advisory can confirm the exact mechanics.
Why unserialize is not automatically RCE
unserialize() instantiates objects named in the string and can trigger magic methods such as __wakeup and __destruct. Actual code execution requires a usable gadget class in the application or its dependencies, so impact depends heavily on the dependency tree; the article notes that large Composer-based projects tend to offer more gadget candidates. The attack also spans two requests — one crafted upload to plant the data, one ordinary page load to misread it — which the article says makes it hard to spot from logs alone.
Mitigation and community patches
PHP's guidance is to set session.upload_progress.enabled = 0 in php.ini, the PHP-FPM pool configuration or the web server config, then restart all PHP workers. The article warns against relying on ini_set() or .user.ini for this, and notes one side effect: applications using the feature for upload progress bars will lose them. It also recommends auditing code for runtime changes to the handler setting, for example by searching the codebase for session.serialize_handler.
For end-of-life PHP versions 5.4 through 8.1, a community project called php2shell-patches ships an unofficial backport with three layers: stripping control characters from names recorded by upload progress, resetting serializer state between requests, and restricting progress decoding to __PHP_Incomplete_Class without autoloading or __wakeup. The project's minimal variant simply disables upload progress, matching PHP's own advice. The article stresses this code is neither an official PHP patch nor validated by the PHP Group.
Why it matters
The vulnerability is unpatched but conditional, and the conditions are cheap to check: one configuration directive and one search through the codebase settle whether a deployment is exposed. The one-line mitigation buys immediate protection without waiting for the regular release. The story also illustrates a recurring pattern — serialization format confusion combined with attacker-reachable writes to the session store is a well-trodden path to unserialize() abuse. Finally, the severity picture is uneven: a third-party score of 9.2 Critical sits alongside a vendor that has published no official score or affected-version list, so patch prioritisation should follow the actual exposure conditions rather than the headline number.
- #php
- #security
- #vulnerability
- #remote-code-execution
- #session-management