PHP ships fixes for two critical bugs at 16:00 CEST today, 21 October, and the only thing really confirmed about them so far is the high score.
The short version
The people with the least PHP expertise sit most exposed in the gap between a vulnerability leak and patch. The controls below are free and won’t take long.
Details
Most of the web runs on PHP and this bug is in a file upload interface that’s like a front door with no lock. An attacker does not need to know which site they are hitting or even the actual software it runs. They send one crafted upload to any server they can find, and that is the entire attack. Anything still on old, unsupported versions of PHP, which is a lot of small businesses and forgotten boxes, has no fix being offered (yet). This is how to lose control to attackers. So let’s talk about what to do.
Known knowns
This much has been confirmed by PHP: the notice on php.net announces two critical vulnerabilities, both rated CVSS v4.0 9.2, and a request that everyone prepare to upgrade immediately after a 16:00 CEST announcement. PHP reserves the right to release earlier if details leak or exploitation starts. Their notice gives no CVE IDs, no component, and no affected versions.
Reported but unconfirmed by PHP: the identifiers CVE-2026-109618 and CVE-2026-109619, and a link to session.upload_progress handling in ext/session. CERT-EU’s advisory says explicitly that it rests on leaks. GMO Flatt Security says its own research overlaps with the reports and warns the write-up may be inaccurate. Huntress reports that watchTowr reproduced CVE-2026-109618. A public exploit exists, and its author claims a second path through the multipart parser that no ini setting closes.
Attacks: Cloudflare’s CTO reported early attacks at 07:43 UTC and shipped stopgap WAF rules to all plans. Huntress and watchTowr had seen none as of their last updates. Tweakers, the Dutch House of Representatives, the Dutch NCSC and Security.NL took their sites offline at 10:35 UTC as that has been the growing “best practice” in the wait.
Disputed: a GitHub repository posted this morning claims the use-after-free described in the public bundle does not exist in released PHP. Kevin Beaumont reads the leaked write-up as probably machine-generated and in the right ballpark on one of the two bugs. The bundle may be wrong, or the real bugs may need further hunting. Either way the patch is the fix.
What now?
Step 1: Inventory
We patch what we know needs it. List every host, container image, and shared-hosting account running PHP, with the version and SAPI (mod_php, PHP-FPM, or CGI) for each. Include the places people forget: CI runners, staging boxes, old WordPress and Joomla installs, vendor appliances with embedded PHP, Windows software bundling its own PHP, and base images in your registry.
PHP supports only 8.2 and later. Huntress names PHP 5, 7, 8.0 and 8.1 as the versions that need upgrading or isolation. CERT-EU advises isolating internet-facing applications from public networks where patching is delayed.
Step 2: Be skeptical about the ini setting
Two people inside the PHP project have said ini mitigation advice being spread is NOT a mitigation.
Core developer Gina Peter Banyard, replying to the suggestion at 02:13 UTC, wrote that the only mitigation is patching or upgrading PHP, and added that taking a server offline for a day is the most sensible option for anyone who can afford it. Release manager Joe Ferguson put it shorter:
ini settings won’t save you
Set session.upload_progress.enabled = 0 anyway. It’s easy and closes the thing that the leak is leaking to us. Upload progress tracking only drives progress bars, which WordPress, Magento and most applications never use anyway. The PHP manual lists the setting as on by default and changeable only per directory, so ini_set() in application code has no effect on it. Put the line in a drop-in under the web SAPI’s conf.d (for example /etc/php/8.3/fpm/conf.d/99-no-upload-progress.ini), restart PHP-FPM or Apache, and verify from a web request. php -i shows the CLI configuration, which is separate. On shared hosting use the control panel’s php.ini editor or a .user.ini, which should take just minutes to apply.
Step 3: Keep multipart away from PHP
The multipart parser runs on every multipart/form-data POST before any application code, so the one configuration change that keeps PHP out of that code entirely is refusing those requests at the web server.
- For nginx, in every server block that passes to PHP:
if ($http_content_type ~* “multipart/form-data”) { return 403; }
- For Apache: a RewriteCond on %{HTTP:Content-Type} matching multipart with a [F] rule.
- For Fastly, a simple recv VCL snippet:
if (req.method == “POST” && req.http.Content-Type ~ “(?i)multipart/form-data”) {
error 403 “Forbidden”;
}An edge requires an origin to refuse connections from everywhere else: lock the origin firewall to your CDN’s published IP ranges.
This breaks every file upload on the site, including the WordPress media library, but it buys time until the patch lands.
If you can go further, allow only GET and HEAD, which leaves the site readable and closes every write path. If you can go further still, stop PHP-FPM and serve a static maintenance page. The maintenance modes inside WordPress and Magento do not help, because PHP parses the request before the application sees the flag.
If uploads must stay open, narrow them: reject multipart on every path except the upload endpoints, set a conservative body cap (for nginx, client_max_body_size) everywhere else, and put admin and internal applications behind a VPN or an authenticating proxy. One rule costs nothing: block any multipart POST whose body contains the field name PHP_SESSION_UPLOAD_PROGRESS, which legitimate traffic never carries. Treat it as a tripwire for one reported path, since a WAF parses multipart bodies differently from PHP.
Signature-based WAF rules for this bug are guesses. Cloudflare only covers traffic that reaches the origin through Cloudflare. Use edge rules to shrink the attack surface until the patch rolls.
Step 4: Depth to defense
A memory corruption bug simply opens the door, and so there is also defense work inside to be done.
Disable the functions you leave unused via disable_functions (system, exec, passthru, shell_exec, proc_open, popen). A memory-corruption exploit can sometimes bypass this, so it raises the cost without guaranteeing safety. Run each PHP pool as its own unprivileged user, keep web roots read-only for that user, and restrict outbound network access from web servers so a shell has nowhere to call home. Confirm PHP workers can only read the credentials they need.
Step 5: Watch for exploitation
Evidence of attempts is visible without knowing the exact bug.
Crashes: repeated worker segfaults in the PHP-FPM log (child exited on signal 11) or Apache error logs, especially clustered in time or from one source. Failed memory-corruption attempts often crash before they succeed.
Request patterns: bursts of multipart POSTs to endpoints that take no uploads, followed by a second quick request from the same source. The upload-progress field lives in the POST body and never reaches the access log, so look at who is POSTing to what.
Process behavior: the PHP or web-server user spawning a shell, sh or bash as a child of php-fpm or apache, or making unexpected outbound connections. On Linux, an auditd or EDR rule on execve from those parents is cheap and high-signal. Huntress points to Florian Roth’s process-watcher as a free option.
Persistence: new or recently modified .php files in upload and cache directories, new cron entries for the web user, and unfamiliar SSH keys. Compare against a known-good deployment hash if you have one.
Keep the logs. If you find something after the patch, you need to look before the patch.
Step 6: Patch when the release lands
The fixed version numbers arrive with the 16:00 CEST announcement. Version numbers in pre-release analysis were guesses, versus what you will get from php.net.
Your distribution’s tracker matters more than the php.net version number. Debian, Ubuntu, Red Hat and the official Docker images backport fixes under their own package versions, and none of them had a page for either CVE as of 20 October. If your PHP comes from Remi’s repository, the PHP Foundation says it will not update today; plan on distribution packages or a source build.
When the release ships: read the official advisory for the real affected component, upgrade, fully restart PHP-FPM or Apache, and confirm the running version from a web-served request rather than the package manager. For containers, rebuild images and redeploy rather than patching in place. Managed hosts will lag. Ask your provider for a date today.
After patching, remove the multipart block and re-enable upload progress only if something needs it.
PHP has been here before
PHP has twice seen this before. In 2012 a request-handling bug (CVE-2012-1823) leaked by accident from PHP’s own bug tracker, the rushed fix was broken within hours, and attackers have hunted it ever since. In 2024 a cousin of that bug on Windows (CVE-2024-4577) was patched on a Thursday and in ransomware by that weekend. Both were simpler than this week’s bug. The pattern is still that a fix arrives and attackers move faster than the people who run the servers, and the conversation is all about widespread infrastructure code nobody maintains.
This post will be updated when the advisory is published.