On 23 October 2026 the PHP project posted a short note. The four packages from 21 October, 8.5.12, 8.4.27, 8.3.36 and 8.2.35, fixed two bugs. They do not fix a third, CVE-2026-115560 (a CVE is a public number so two people can mean the same bug). PHP calls the third one unlikely. It still asked anyone who turned a setting off on Wednesday to leave that setting off until the next regular bugfix release. I did not attack a server. I read the note, the 21 October advisory, Cloudflare’s update, and the session manual.
If you only do one thing this weekend, do not turn session.upload_progress.enabled back on just because php -v now prints 8.5.12, 8.4.27, 8.3.36 or 8.2.35. That switch (a line in PHP’s configuration that turns a built-in feature on or off) was the mitigation PHP already listed on 21 October for one of the emergency bugs. On 23 October, PHP said the same line fully protects you from this newer, narrower bug, and that a full write-up of CVE-2026-115560 will ship with the next regular release. There is no version number to install for it yet. I checked the PHP news archive on 25 October. Nothing dated 24 or 25 October replaced the note.
The longer piece on the two emergency bugs, and on why updating WordPress does not touch them, is already on the site: Updating WordPress does not close PHP2Shell. This page is only the correction to the last step of that one. The version bump was necessary. It was not the end of the week.
Three numbers, and only two of them have a package

A release (a numbered build of PHP you can install) is not the same object as an advisory (a written description of a bug). On 21 October, PHP shipped both: the packages, and a security advisory for CVE-2026-109618 and CVE-2026-109619. People nicknamed that pair PHP2Shell. On 23 October, PHP shipped writing only. The title on the news page is “Informational advisory: Session upload progress.” Informational, here, means PHP is telling you about a bug it has not packaged a fix for yet.
| What | Number | What 8.5.12, 8.4.27, 8.3.36 and 8.2.35 do with it |
|---|---|---|
| Out-of-memory cleanup treats half-built request data as finished | CVE-2026-109618 | Fixed, if you installed the package and restarted every PHP worker |
| A later request reuses state whose memory was already freed | CVE-2026-109619 | Fixed, on the same condition |
| Session upload progress plus a runtime switch of the session format | CVE-2026-115560 | Not fixed. The code is still in those packages, including 8.5.12 |
A worker (one long-lived copy of PHP that handles many requests, one after another) has to be restarted after a package install, or the old copy keeps running. “The file on disk is 8.5.12” and “the process answering requests is 8.5.12” are two checks.

Cloudflare’s blog, in an update dated 23 October on a post first published 21 October, says this third issue “affects fully patched PHP releases, including 8.5.12, and will be fixed in PHP’s next regular release.” That sentence and PHP’s sentence are about the same fact. “Affects 8.5.12” means the bug is still in that release. It does not mean every site running 8.5.12 can be taken over today. PHP’s next sentences are the ones that say when it can.
A session is a slip of paper between two clicks
HTTP (the protocol a browser uses to ask a server for a page) does not remember you. Each request arrives alone. A session (the server’s memory of “this is the same person as last time”) is how a login, a cart, or a half-finished form survives the gap. The usual way it works: the server sends a cookie (a small name and value the browser will send back on the next request). The name is often PHPSESSID. The value is an id. The actual data sits on the server, looked up by that id.

session_start() (the function call that says “load that slip for this request”) is what ordinary application code uses. You do not need to know the file format to use it. You do need the file format to understand this bug, because the bug is two readers disagreeing about the same bytes.
Serialize means turn the slip into bytes, and PHP ships more than one dialect
Serialize (turn a bag of names and values into a line of bytes that can be stored) is a necessary step, because a disk or a cache stores bytes, not a live array. Unserialize (turn those bytes back into names and values) is the reverse. A serialize handler (the dialect that does both directions) is chosen by the setting session.serialize_handler.
PHP’s own session manual, the page I read on 25 October 2026, names the disagreement in public, without describing this bug. The php handler cannot store a root-level session key that contains a | character. The manual says using such a key fails the session write, with a warning as of PHP 8.5.0. The php_serialize handler does not have that limit. Same slip of paper, two dialects, and a character that is punctuation in one dialect and just another letter in the other.
That manual page is not the advisory. I am not going to invent the exploit from it, and I am not going to copy a proof-of-concept (a sample request someone published to demonstrate the bug). PHP said it will publish the full advisory with the next release. Until then, the conditions PHP already printed are the part a reader can check. The configuration manual’s default for session.serialize_handler is php. A distribution (the packaged PHP from Ubuntu, Debian, or a host) can change a default. Do not trust this paragraph over your own machine. Print the value.
php --ri session | grep -i serialize_handlerphp --ri session (a command that prints the session settings of the PHP you just ran) is the right first print. Then remember the trap from the other post: the PHP in your shell and the PHP inside the web worker can be different builds. Check the worker too, from a page the site itself runs, or from the host’s panel.
Upload progress writes on that slip before your program starts
Session upload progress (a built-in that records how far along a file upload is, and stores that record in the session) ships turned on. It runs while PHP is still reading the request. The application does not have to call session_start() for it to run. That is why an admin checkbox inside WordPress, labeled something like “allow uploads,” is the wrong switch. The feature is in the engine (the PHP program), earlier than your code.
A multipart body (a request split into named parts, which is how a form that includes a file is sent) is the kind of request this feature watches. The field it looks for has a name. The setting for that name is session.upload_progress.name. If you have never heard of it, you are on the default name. Remember the default. Cloudflare’s rule, below, cares about it.
The 21 October advisory already said this feature can run before ordinary session startup, and that turning it off blocks the confirmed session paths of CVE-2026-109619, not every other path of that bug. The packages closed that bug properly. The 23 October note is a different claim, about a different bug, and it uses the same switch: leave the feature off, and this third path is closed too.
The door opens only if three things are all true
PHP’s words, not mine. The issue can only occur under an unusual combination of configuration and application code. All three of these have to be true:
- The configuration sets
session.serialize_handlertophp_binaryorphp_serialize. Configuration means php.ini, the pool, or the server config, not a line that runs later inside the request. - The application then switches that handler to
phpat runtime withini_set()before callingsession_start().ini_set()(a function that changes a setting for the rest of this request) is the runtime switch. A comment in a config file is not a runtime switch. - Session upload progress is still enabled. It is enabled by default, so this third one is the easy one to satisfy by doing nothing.

PHP’s next sentence is the one headline writers skip. Applications that never change the serialize handler at runtime can keep the feature enabled. If you have read your code and your plugins and nobody calls ini_set on session.serialize_handler, PHP says you may leave upload progress on. If you have not read it, you do not get to use that sentence yet.
I did not audit WordPress core, Drupal, Laravel, or any plugin directory for that call. “Popular app” is not a measurement. Search the tree you actually deploy, including plugins and anything you pulled in with Composer (the PHP dependency installer).
rg -n "serialize_handler" .rg (ripgrep, a search tool) is enough. If you do not have it, grep -R "serialize_handler" . is the same question. You are looking for ini_set, ini_alter, or a config file that sets the handler to php_binary or php_serialize. A match is not an exploit. A match is the moment you stop guessing and read those lines.
Why this one did not get an emergency package
PHP’s reason is in the note: “Since this setup is unlikely in practice, we are handling it in the regular release cycle and will publish a full advisory for CVE-2026-115560 with the next release.” Unlikely is their word for the combination, not a promise about the damage if the combination is yours. A regular release (the normal bugfix train, as opposed to the out-of-cycle security packages on 21 October) does not have a public version number for this fix as of 25 October 2026. Do not invent one in a ticket.
I am also not going to borrow a severity score. The two emergency bugs were rated 9.2 on CVSS v4 (a 0-to-10 severity scale, not a prediction that you will be hit today) by the PHP project. The 23 October note does not print a score for CVE-2026-115560. A blog that invents one is not informing you.
The setting has to be in force before the request is read
If you already set session.upload_progress.enabled=0 on 21 October, in a place that applies before PHP parses the request, PHP’s 23 October note says keep it and do nothing else for this bug. “Keep it” is the sentence people will undo, because the package felt like permission to turn the feature back on.
The place matters, and the 21 October advisory already said so. Use php.ini, an FPM pool (PHP-FPM is the separate pool of workers that Apache or nginx talks to), or the server config. Restart every worker afterward. Do not rely on ini_set() for this particular off switch. Do not rely on an FPM .user.ini (a per-directory file that PHP reads too late to affect request parsing). The feature runs during parsing. A switch that flips after parsing is a switch that flips after the feature has already run.
session.upload_progress.enabled = 0That line is the whole mitigation PHP offered for CVE-2026-115560. It is not a mitigation for every path of the two bugs from 21 October. Those needed the package. If you are on 8.1 or older, you still do not have an official package for the two emergency bugs. The other post covers that. This setting does not promote an old branch into a supported one.
On shared hosting (a machine where you cannot replace PHP yourself), the ticket has to name the setting and ask for a worker restart. “Please update WordPress” is still the wrong sentence. “Please set session.upload_progress.enabled to 0 in the pool, and restart PHP” is the sentence for this bug, if you cannot prove the three conditions are absent.
A firewall rule is not the missing package
A WAF (a web application firewall: a filter in front of your server that blocks requests it judges hostile) can buy time. It is not a release. Cloudflare wrote, in that 23 October update, that customers are protected against known exploit attempts for this issue if the site uses PHP’s default upload-progress field name. Customers who changed session.upload_progress.name are not covered by that rule. The rule they name is the existing one, “PHP Remote Code Execution Attack (CVE-2026-109618, CVE-2026-109619) #6.” So the filter is watching for known attempts at the default name. A renamed field walks past that particular rule. Turning the feature off does not care what the field is called.

Cloudflare also said the rules went up at 03:02 UTC on 21 October, about nine hours before the emergency disclosure, on free and paid plans. The same post says analysts keep updating rules because attackers change payloads. A rule that matched yesterday’s shape is not a property of your PHP version.
One number I will not print as a fact: a “one million attempts a minute” headline. I did not read a primary post that says that rate. What I can attribute is a running total. BetaNews, on 23 October 2026, quoted Cloudflare’s CEO, Matthew Prince, on the two bugs announced 21 October: thousands of attempts across Cloudflare in the ten hours before the announcement, tens of thousands within 45 minutes after it, hundreds of thousands within two hours, and millions by the time of that post. That count is about CVE-2026-109618 and CVE-2026-109619. It is not a measurement of CVE-2026-115560. PHP has not said the third issue is being exploited. Do not paste the Wednesday chart under Thursday’s number.
What to check, in this order
- Confirm the worker, not just your shell, is on 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or on a distribution package whose changelog names CVE-2026-109618 and CVE-2026-109619. If it is not, the emergency bugs are still the first problem. This page does not replace that install.
- Search the deployed tree for
serialize_handler. If nothing switches it at runtime, PHP says this third vector does not apply, and you may keep upload progress on. - If something does switch it, or if you cannot finish the search because a plugin is opaque, set
session.upload_progress.enabled=0where it applies before parsing, and restart every worker. Leave it off until the next regular PHP release, or until you have read the code. - If you turned that setting back on after installing 8.5.12, turn it off again until step 2 is done. The package did not close this bug.
- If you renamed
session.upload_progress.nameand you are counting on Cloudflare’s rule #6, you are outside the case Cloudflare said it covers. The off switch still works. - Write down the date you checked. “We patched on Wednesday” will be the wrong sentence in a week, when the regular release lands and this page needs a version number it does not have today.
What this page is not saying
Installing the 21 October release was the right move. It closed two bugs that PHP rated critical, that do not need a login, and that hit PHP itself rather than one application. This page does not walk that back.
This page is also not saying every WordPress site is on fire from CVE-2026-115560. PHP’s condition is unusual on purpose: a non-default dialect in the config, then a switch back to the php dialect at runtime, with upload progress still on. Most applications never touch the handler. “Most” is PHP’s judgment, which they wrote as “unlikely in practice.” It is not a scan of your disk.
I am not publishing a request that triggers it. The patch is not public yet. A recipe under an unfixed bug teaches the wrong reader more than it teaches you. The check above is the part that changes what you do today.
Common questions about CVE-2026-115560
Does PHP 8.5.12 fix CVE-2026-115560?
No. The 21 October packages fixed CVE-2026-109618 and CVE-2026-109619. PHP says CVE-2026-115560 will be fixed in the next regular release, with a full advisory.
Should I turn session upload progress back on after updating?
Not until you have searched the code you deploy for a runtime switch of session.serialize_handler. If nothing switches it, PHP says you may keep upload progress on.
Where do I set session.upload_progress.enabled to 0?
In php.ini, an FPM pool, or the server config, then restart every PHP worker. Do not rely on ini_set() or a .user.ini file, because they apply after the request is parsed.
Does Cloudflare’s WAF rule cover CVE-2026-115560?
Cloudflare says known exploit attempts are covered if the site uses PHP’s default upload-progress field name. A site that renamed session.upload_progress.name is outside that case.