Status, 22 October 2026, 14:30 UTC: PHP 7.4 and newer patched. Enhance has published PHP 7.4.33-1, 8.0.30-1 and 8.1.34-1, which carry PHP’s backported fixes for these end-of-life versions. They are installed and running on every Kiravo server, alongside the 8.2 to 8.5 patches from yesterday. Sites on PHP 7.4 or newer are protected, with nothing for you to do.
Earlier updates: on 21 October at 16:15 UTC, PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 were installed on every Kiravo server. At 13:15 UTC, a WAF rule blocking the upload progress field used in these attacks went live on all servers. At 10:30 UTC, the fix was still scheduled for 14:00 UTC.
The PHP security team has released fixes for two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619, both rated CVSS v4.0 9.2. Details leaked before the patch was ready, and Cloudflare reported exploitation attempts before the release.
These are bugs in PHP itself, not in WordPress or a plugin. A site can be fully up to date and still be exposed until its PHP binary is patched and restarted.
What PHP has confirmed
- CVE-2026-109618, code execution through out-of-memory corruption (GHSA-w8hw-w9fx-j79w). Running out of memory can interrupt PHP while internal request data is only partly initialized. Request cleanup may then treat that data as valid.
- CVE-2026-109619, code execution through stale global state (GHSA-6wmf-4rv5-p3rp). Internal state from one request can outlive the memory behind it, and a later request handled by the same worker may use it.
- Both allow remote code execution without authentication. Every PHP installation that serves web requests is at risk: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. PHP rates the risk highest for mod_php, where a demonstrated exploit runs before any application code does.
- Fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 and older get no official release. The PHP security team has published minimal source backports for 7.4, 8.0 and 8.1 for people who build PHP themselves.
- No configuration change fully mitigates either bug. In PHP’s words, “updating is the only safe choice.”
What we did for Kiravo clients
If your site runs PHP 7.4 or newer, you don’t need to do anything.
- Patched PHP on every server. Enhance, our control panel vendor, published patched PHP packages after PHP’s release. We installed them on all servers and restarted every PHP container, so no site is still running the vulnerable code.
- Patched the end-of-life versions too. On 22 October, Enhance published PHP 7.4.33-1, 8.0.30-1 and 8.1.34-1, built with PHP’s backported fixes. We installed them on all servers and restarted PHP again.
- The early mitigations stay in place. Session upload progress has been off by default since Enhance 12.26.1, which we applied this morning, and our web application firewall still blocks any request carrying PHP’s upload progress field (
PHP_SESSION_UPLOAD_PROGRESS). The patch is the fix. These remain as a second layer. - Isolation limits the damage. Every Kiravo site runs in its own container. A successful exploit is confined to that one site’s container unless it is chained with a separate kernel privilege-escalation bug, so it cannot reach other sites on the same server.
If your site runs PHP 7.4, 8.0 or 8.1, it is patched against these two bugs, but it is still end of life. This backport was a one-off for a critical incident, and the next PHP vulnerability may not get one. Plan a move to a supported version from your control panel. PHP 8.2 reaches end of life on 31 December 2026, so choosing 8.3 or newer saves you a second move in ten weeks. Test your site afterwards, since older plugins and themes sometimes need updating. If you would like a hand with this, contact us and we’ll do it with you.
One side effect: with upload progress disabled, upload progress bars that depend on PHP’s built-in session upload progress may stop updating. Uploads themselves still work. WordPress doesn’t rely on this feature, so most sites won’t notice any difference. We’re leaving it off.
Patching your own servers
- Upgrade PHP to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 on every server. Distributions and LTS vendors received the patches in advance, so check your vendor’s packages first.
- Ondřej Surý’s PPA: some mirrors lag behind, so check with
apt-cache policythat you are getting the new version. - Static builds such as FrankenPHP need a new release, because
aptwon’t patch them.
- Ondřej Surý’s PPA: some mirrors lag behind, so check with
- Restart every long-running PHP process. That includes PHP-FPM, Apache with mod_php, Laravel Octane, and queue workers. A process that was already running keeps the vulnerable code in memory until it restarts.
- Move off PHP 8.1 and older. If you can’t yet, install a backported build. On Enhance, that’s PHP 7.4.33-1, 8.0.30-1 or 8.1.34-1, which the commands below pick up. Otherwise, ask your LTS vendor, or build from PHP’s source backports for 7.4, 8.0 or 8.1.
- Check for signs of compromise. Exploitation began before the patch. Look for unexpected PHP files in upload and cache directories, new admin users, and unusual multipart POST requests in your access logs.
If you run Enhance, on every server:
apt update
apt upgrade -y
ecp restart-php
ecp restart-php waits for a lock on each website, so it can take a few minutes on busy servers.
You can leave session upload progress disabled after patching. Very few applications use it.
If you can’t patch yet
These steps reduce exposure to specific attack paths. PHP is explicit that they don’t make an installation safe, so treat them as a bridge to the update, not a substitute for it.
1. Disable session upload progress (CVE-2026-109619)
This blocks the confirmed session-based paths, though not every variant. The setting has to apply before PHP parses the request, so ini_set() in your application and FPM .user.ini files won’t work. Set it in configuration.
In a php.ini drop-in (for example /etc/php/8.3/fpm/conf.d/99-cve-2026-109618.ini):
session.upload_progress.enabled = 0
Or per PHP-FPM pool:
php_admin_flag[session.upload_progress.enabled] = off
For FrankenPHP, add it to the global frankenphp block in your Caddyfile:
{
frankenphp {
php_ini session.upload_progress.enabled 0
}
}
On PHP 8.5, also set fatal_error_backtraces = 0, which blocks the confirmed fatal-error backtrace path.
Then restart every PHP worker and confirm the change took effect. Note that php -i on the command line reads the CLI configuration, not FPM’s:
php-fpm8.3 -i | grep session.upload_progress.enabled
Pool-level overrides won’t show up there. To check those, look at a phpinfo() page served through the site itself.
If you run Enhance, version 12.26.1 turns upload progress off for you. The commands above install it.
2. Remove the PHP memory limit and cap request size (CVE-2026-109618)
The attacker-controllable way to trigger this bug is pushing PHP past its memory limit, so PHP advises removing that limit and keeping requests small. A genuine out-of-memory failure can still reach the bug. Per PHP-FPM pool:
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 7M
Use post_max_size = 32M on sites that accept file uploads, and keep upload_max_filesize below it. php_admin_value stops WordPress and other applications from setting a memory limit back. Check that no pool, directory or application setting reintroduces a finite one.
Without a PHP memory limit, a runaway request can use all the memory it can get. Put a container or cgroup memory limit around PHP instead, ideally one that kills only the affected worker. Don’t use RLIMIT_AS or RLIMIT_DATA for this, since they can cause the very allocation failure the bug depends on.
3. Block multipart requests where you don’t need them
This cuts off the multipart request bodies (file uploads and multipart form posts) named in the original leak. It also breaks file uploads and multipart forms, so apply it only to sites that don’t accept them, or to a short list of paths you have checked.
nginx. In the http {} block:
map $http_content_type $is_multipart {
default 0;
~*multipart 1;
}
Then in each server {} block that passes requests to PHP:
if ($is_multipart) {
return 403;
}
If an error_page 403 directive routes back to PHP, use return 444; instead so the request never reaches PHP.
Apache 2.4:
<If "req('Content-Type') =~ /multipart/i">
Require all denied
</If>
Use req('Content-Type') as shown. %{CONTENT_TYPE} doesn’t reliably match here.
Caddy:
@multipart header_regexp Content-Type (?i)multipart
respond @multipart 403
Check that the block works. This should return 403:
curl -s -o /dev/null -w '%{http_code}\n' -F test=1 https://example.com/
If you allowlist upload endpoints such as /wp-admin/async-upload.php so editors can keep working, those endpoints stay exposed until you patch. Keep the list short, and limit access to logged-in users or known IP addresses where you can.
4. Use a WAF, if traffic can only reach you through it
If you run ModSecurity, this rule, shared on the Enhance community forum, rejects requests carrying the session upload progress field:
SecRequestBodyAccess On
SecRule ARGS_NAMES "@streq PHP_SESSION_UPLOAD_PROGRESS" \
"id:1026109618,phase:2,t:none,deny,status:403,log,\
msg:'php2shell: PHP_SESSION_UPLOAD_PROGRESS field blocked'"
Cloudflare has reportedly deployed managed WAF rules for this on all plans. Any WAF, Cloudflare’s or your own, only helps if your origin rejects traffic that doesn’t come through it. If attackers can reach your server’s IP address directly, the WAF is bypassed.
What doesn’t help
file_uploads = Off. PHP still parses the request body.enable_post_data_reading = Off.- Hiding errors with
error_reporting,display_errorsor@. - Middleware inside your application. The bug triggers before your code runs.
If you take a site offline, stop the web server or return a 503 from it. Don’t just disable the PHP handler. Apache and nginx may then serve your .php files as plain text, including any credentials in wp-config.php.