On 21 October 2026 PHP shipped 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix PHP2Shell: CVE-2026-109618 and CVE-2026-109619, two memory-safety bugs in PHP’s core, both rated CVSS v4.0 9.2, that allow unauthenticated remote code execution. They live below your framework, so updating WordPress, Drupal or Laravel changes nothing. Amazon saw a first exploitation attempt on 17 October, four days before the patch.
The news side is in my 21 October security-day roundup. This post is the hands-on part: find the PHP that really serves your requests, patch it per environment, mitigate if you can’t yet, and hunt in your logs. Every command and directive comes from the advisories, vendor docs or my own checks of the package indexes on 26 October.
1. The Problem: Two Bugs Below Your Code
php.net’s advisory is blunt: all PHP installations serving web requests are at risk, including PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed. The risk is highest on mod_php, where an unauthenticated request can trigger the attack before any application code runs.
You only need four concepts to make good decisions this week. I’m keeping exploit mechanics at the level the advisories publish.
CVE-2026-109618: RCE via OOM corruption
GHSA-w8hw-w9fx-j79w · CVSS v4.0 9.2
PHP handles out-of-memory errors with longjmp(). If memory runs out while request data is only partly initialised, request shutdown later treats that half-built data as valid. The advisory validated full RCE over HTTP against mod_php with default limits; FPM is susceptible by source analysis, with no complete FPM exploit shown.
CVE-2026-109619: RCE via stale global state
GHSA-6wmf-4rv5-p3rp · CVSS v4.0 9.2
A worker keeps global state that points to memory owned by one request. After a fatal error, such as an OOM or ‘Maximum execution time exceeded’, that memory is freed, and a later request on the same worker can use the stale state before normal initialisation resets it. Confirmed early consumers include INI diagnostics and session upload progress.
CVE-2026-115560: narrow, and not fixed yet
php.net informational advisory · 23 Oct
Needs an unusual setup: session.serialize_handler set to php_binary or php_serialize in config, switched to php with ini_set() before session_start(), with upload progress still enabled. The 21 October releases do not address it; the full advisory comes with the next regular release.
Why worker reuse matters
PHP-FPM, mod_php, FrankenPHP, LiteSpeed
Long-lived workers serve many requests, so one bad request can poison the next. The advisory says the producer and consumer requests must hit the same worker; multiple workers and recycling lower the odds per attempt but do not remove the condition.
Exposure by SAPI, according to php.net and the GHSA advisories
| How PHP serves requests | Exposure per the advisories | What to restart after patching |
|---|---|---|
| Apache mod_php | Highest: RCE demonstrated with default limits, before any app code runs | apache2 / httpd |
| PHP-FPM (nginx, Apache proxy) | Susceptible by source analysis; no complete FPM exploit shown for CVE-2026-109618 | php8.x-fpm / php-fpm, every pool |
| FrankenPHP, LiteSpeed (LSAPI), php-cgi | Listed at risk by php.net; FrankenPHP and LSAPI ‘likely susceptible’ per the GHSA | The server itself (FrankenPHP 1.13.2+), lsphp |
| CLI (cron, queues, Artisan) | Not an HTTP entry point, but the same engine: patch it too | Queue workers, Horizon, Octane, Supervisor jobs |
Timeline (dates as published by each source)
A popular one-line summary merges two bugs
Some patch guides describe PHP2Shell as ‘a request that hits memory_limit at the wrong moment, leaving stale memory for the next request’. That blends the two CVEs. CVE-2026-109618 corrupts the request that ran out of memory; CVE-2026-109619 is stale state that a later request reuses, and its triggers include execution timeouts, not only memory. It matters for mitigation: memory_limit=-1 targets the first, disabling upload progress closes confirmed paths of the second.
2. Step 1: Find the PHP That Actually Serves Requests
On a typical server I find three PHPs: the CLI on the PATH, one or more php-fpm pools, and sometimes a mod_php nobody remembers enabling. They can be different packages on different versions, and only the ones that answer HTTP decide whether you are exposed.
Fixed builds I verified (26 October 2026)
| Source | Fixed version or package revision | Note |
|---|---|---|
| php.net 8.5 / 8.4 / 8.3 / 8.2 | 8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 | 8.2 security support ends 31 Dec 2026 |
| Debian 13 trixie (php8.4) | 8.4.27-1~deb13u1 | DSA-6574-1 |
| Debian 12 bookworm (php8.2) | 8.2.35-1~deb12u1 | DLA-4848-1 (Debian LTS) |
| Ubuntu 26.04 LTS (php8.5) | 8.5.4-0ubuntu1.5 | USN-8948-1, backport |
| Ubuntu 24.04 LTS (php8.3) | 8.3.6-0ubuntu0.24.04.13 | USN-8948-1: php -v still says 8.3.6 |
| Ubuntu 22.04 LTS (php8.1) | 8.1.2-1ubuntu2.28 | USN-8948-1: patched 8.1 |
| Surý repo / PPA, legacy branches | 8.1.34-9 · 1:8.0.30-25 · 1:7.4.33-31 | Backports built 21 Oct; same php -v as before |
| Docker official php image | php:8.5.12-*, 8.4.27-*, 8.3.36-*, 8.2.35-* | No patched php:8.1 tag (last updated Dec 2025) |
| FrankenPHP | 1.13.2 | Images and static binaries rebuilt on 21 Oct |
| Remi (Fedora, EL 8+) | 8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 | remi-modular and remi-safe (SCL), 22 Oct |
Inventory: every PHP on the box and the package behind it
Run it on each host and inside each container. The package revision is what proves a backport, not the version string.
# 1. Which branches are installed (Debian/Ubuntu layout)
ls /etc/php/
php -v # CLI only: the binary first on your PATH
# 2. The binaries that serve web requests
php-fpm8.4 -v # Debian/Ubuntu: one php-fpmX.Y per branch
php-fpm -v # RHEL, Alma, Rocky, Remi module streams
apachectl -M 2>/dev/null | grep -i php # php_module = mod_php (httpd -M on RHEL)
# 3. Package revisions: what matters when the fix is a backport
dpkg -l 'php*' 'libapache2-mod-php*' | awk '/^ii/ {print $2, $3}'
rpm -qa 'php*' | sort
# 4. Containers: what is running, not what the tag points to today
docker exec <container> php -v
docker run --rm --pull=always php:8.4-fpm php -v
# 5. From outside, only if expose_php is on
curl -sI https://example.com | grep -i '^x-powered-by'What FPM really runs, without publishing a phpinfo() page
Red Hat’s bulletin warns that php -i only shows the CLI configuration. This asks the FPM socket directly, so nothing is exposed through the web server, and then lists processes still mapping an old PHP binary or module after an upgrade.
# cgi-fcgi comes from libfcgi-bin (Debian/Ubuntu) or fcgi (EPEL)
sudo tee /var/www/php2shell-check.php >/dev/null <<'EOF'
<?php
header('Content-Type: text/plain');
echo PHP_VERSION, ' ', PHP_SAPI, PHP_EOL;
foreach (['session.upload_progress.enabled', 'memory_limit',
'post_max_size', 'fatal_error_backtraces'] as $k) {
echo $k, ' = ', var_export(ini_get($k), true), PHP_EOL;
}
EOF
sudo env SCRIPT_FILENAME=/var/www/php2shell-check.php REQUEST_METHOD=GET \
cgi-fcgi -bind -connect /run/php/php8.4-fpm.sock # RHEL: /run/php-fpm/www.sock
sudo rm /var/www/php2shell-check.php
# After apt/dnf: processes still running a replaced PHP binary or module
sudo grep -l 'php.*(deleted)' /proc/[0-9]*/maps 2>/dev/nullWhat ‘patched’ looks like
php-fpmX.Y -v (or the FPM check above) shows a fixed version or, on backports, a fixed package revision; the module Apache loads comes from a fixed package; and the /proc grep returns nothing. If a PID shows up there, that process is still running the old code.
3. Step 2: Patch per Environment
Same goal everywhere: get a fixed build under the process that answers HTTP, then restart it. What changes is how the build reaches you.
Debian and Ubuntu (distro or Surý)
DSA-6574-1 · DLA-4848-1 · USN-8948-1 · packages.sury.org
Debian fixed php8.4 in trixie and php8.2 in bookworm; Ubuntu shipped USN-8948-1 on 21 October for 22.04, 24.04, 26.04 and 26.10. If you use Ondřej Surý’s repository or PPA, its index has fixed builds dated 21 October for every branch from 7.4 to 8.5. Laravel’s Forge notes that unattended-upgrades only pulls Ubuntu’s own security pocket, so third-party PHP repos are not patched automatically. Repeat for every installed branch, even unused ones.
sudo apt-get update
apt-cache policy php8.4-fpm # Candidate = the fixed version or revision?
sudo apt-get install --only-upgrade -y \
-o Dpkg::Options::="--force-confold" \
$(dpkg -l 'php8.4*' | awk '/^ii/ {print $2}')
sudo systemctl restart php8.4-fpm # mod_php: sudo systemctl restart apache2RHEL, Alma, Rocky (AppStream or Remi)
RHSB-2026-013 · Remi, 22 Oct
Red Hat’s bulletin lists RHEL 8, 9 and 10 as affected (RHEL 7 only by CVE-2026-109619) and, as of its 23 October update, says some fixes are out with more in progress. Remi published 8.5.12, 8.4.27, 8.3.36 and 8.2.35 on 22 October in remi-modular and as Software Collections in remi-safe. If your stream has no fix yet, apply step 3 today.
sudo dnf upgrade 'php*' # AppStream stream or Remi remi-modular sudo dnf upgrade 'php84*' # Remi Software Collections (remi-safe) rpm -q --changelog php-fpm | grep -m2 'CVE-2026-10961' # if your vendor lists CVEs sudo systemctl restart php-fpm httpd # SCL: php84-php-fpm
Official Docker images
Rebuild, don’t restart · pin tag + digest
A restart reuses the same image, so a running container keeps the PHP it was built with. The official php tags for 8.5.12, 8.4.27, 8.3.36 and 8.2.35 were on Docker Hub by the evening of 21 October (UTC) and have been rebuilt since. Pin the exact patch tag plus its digest so builds are reproducible, and let Renovate or Dependabot bump it. If you build FROM a third-party PHP image, check that vendor’s changelog.
# Get the digest of the fixed tag, then pin both in the Dockerfile docker buildx imagetools inspect php:8.4.27-fpm | grep -m1 Digest # FROM php:8.4.27-fpm@sha256:<digest> # Rebuild without cached base layers and recreate the containers docker compose build --pull --no-cache docker compose up -d --force-recreate docker compose exec app php -v
Shared hosting and cPanel
The host patches; you verify
You can’t patch PHP yourself here. In cPanel, MultiPHP Manager changes which version a domain uses, not the patch level of that version. Tanium reports that EasyApache 4 v25.91 carries the fix; I could not find cPanel’s own note, and found no confirmed status for CloudLinux alt-php. Send your provider three precise questions:
Subject: PHP2Shell (CVE-2026-109618 / CVE-2026-109619) 1. Which PHP build serves my account (ea-phpXX, alt-php, lsphp), at which package revision? 2. Does it include the 21 Oct 2026 fixes, and were PHP-FPM / LiteSpeed workers restarted? 3. Is session.upload_progress.enabled off until the next PHP release (CVE-2026-115560)?
WordPress and Drupal
Core and plugin updates don’t fix PHP
The bug is in PHP, so updating core or plugins does nothing; Vercel’s bulletin says the same about application code. Wiz says it confirmed unauthenticated RCE against Drupal and WordPress during its research. Without SSH, open Tools → Site Health → Info → Server: it shows the PHP version and SAPI. On managed hosting, ask for the package revision, not just ‘we run 8.3’.
Laravel (Forge, queues, Octane)
Laravel Forge advisory, Oct 2026
Forge’s automatic security updates do not patch PHP: update each version from the server’s PHP tab or over SSH. Long-running CLI processes keep the old binary until they restart: queue workers, Horizon, Octane, Reverb. If Octane runs on FrankenPHP, update FrankenPHP itself to 1.13.2 or later.
php artisan queue:restart php artisan horizon:terminate php artisan octane:reload
FrankenPHP, Windows and AWS
FrankenPHP 1.13.2 · php.net -1 builds · AWS 2026-143
FrankenPHP 1.13.2 (21 October) rebuilt its images and static binaries with the fixed PHP versions. On Windows, use the php.net builds; the 26 October -1 rebuilds also update Brotli for a separate cURL decompression bug. On AWS, Elastic Beanstalk has updated platform versions, Lightsail needs new instances from updated blueprints, and Lambda custom runtimes or Bref must be rebuilt and redeployed.
4. Step 3: Mitigate If You Can’t Patch Today
php.net lists measures that reduce exposure to specific attack paths ‘but do not make an installation safe’. Put them where PHP reads them before the request is parsed: php.ini, the FPM pool or the Apache config. php.net is explicit that ini_set() and FPM’s .user.ini don’t count.
PHP-FPM pool: settings an app can’t override
Straight from the php.net advisory and GHSA-6wmf-4rv5-p3rp. php_admin_value and php_admin_flag can’t be changed later with ini_set().
; /etc/php/8.4/fpm/pool.d/www.conf (RHEL: /etc/php-fpm.d/www.conf) php_admin_flag[session.upload_progress.enabled] = off ; -1 only together with a cgroup or container memory cap (below) php_admin_value[memory_limit] = -1 ; 8M if the app takes no uploads, 32M if it does php_admin_value[post_max_size] = 8M php_admin_value[upload_max_filesize] = 6M ; PHP 8.5 only, older branches don’t know this directive: ; php_admin_flag[fatal_error_backtraces] = off ; Last resort if performance doesn’t matter (GHSA-6wmf-4rv5-p3rp): ; pm.max_requests = 1 # No other pool, conf.d file or vhost may put a finite limit back grep -rn 'memory_limit\|upload_progress' /etc/php/8.4/ sudo systemctl restart php8.4-fpm
Apache mod_php, plus the cgroup cap memory_limit=-1 needs
php.net wants an external memory boundary that kills only the affected worker. systemd’s MemoryMax= sets the cap; OOMPolicy=continue keeps the service up when the kernel kills one process (the default policy stops the whole unit). Size the cap to your machine.
# /etc/apache2/conf-available/php2shell.conf (RHEL: /etc/httpd/conf.d/)
<IfModule php_module>
php_admin_flag session.upload_progress.enabled off
php_admin_value memory_limit -1
php_admin_value post_max_size 8M
php_admin_value upload_max_filesize 6M
</IfModule>
sudo a2enconf php2shell && sudo systemctl restart apache2
# sudo systemctl edit php8.4-fpm (or apache2 / httpd)
[Service]
MemoryMax=2G
OOMPolicy=continueBridges around the config
- WAF as a bridge: Cloudflare (all plans with the WAF, Free included, according to coverage of its announcement), the AWS WAF PHP managed rule group (pinned versions must be updated) and Vercel’s WAF shipped rules. They only see traffic that passes through them, so lock the origin to the proxy’s IP ranges.
- Block multipart where you can: Amazon suggests blocking multipart uploads on PHP deployments you can’t patch yet, after checking the impact on your app. At minimum cap request size at the proxy (client_max_body_size in nginx, LimitRequestBody in Apache); php.net also asks for limits on input fields, multipart parts and headers.
- Recycle workers, as a last resort: the CVE-2026-109619 advisory suggests pm.max_requests=1 ‘if performance is not a factor’. It lowers the success rate per attempt; it does not remove the condition.
- Fix your own fatals: php.net asks you to fix attacker-reachable fatal errors and execution timeouts, and to remove invalid or deprecated per-request settings that emit diagnostics. Hiding them with error_reporting, display_errors or @ doesn’t help.
CVE-2026-115560: not fixed by the 21 October releases
php.net’s 23 October informational advisory covers a narrow third RCE vector; the full advisory ships with the next regular release. It needs session.serialize_handler set to php_binary or php_serialize in config and switched to php with ini_set() before session_start(), with upload progress on. The mitigation is the same line as above, session.upload_progress.enabled=0, and php.net says apps that never switch the handler can keep the feature. My take: turn it off unless you render upload progress bars, because it also closes confirmed CVE-2026-109619 paths, and the GHSA calls disabling it prudent even after patching. Quick check: grep -rn serialize_handler across your code and PHP config.
Mitigations that bite back
memory_limit=-1 without an external cap turns an exploit attempt into a memory-exhaustion outage, and php.net warns against RLIMIT_AS or RLIMIT_DATA, which can cause the very allocation failure you’re avoiding. Setting fatal_error_backtraces below PHP 8.5 adds an unknown directive, the kind of invalid setting the advisory tells you to remove. And restart every worker, as php.net says: until it restarts, a worker keeps the old settings.
5. Step 4: Detect What Already Hit You
No public signature catches PHP2Shell reliably, and the CVE-2026-109619 advisory warns that a clean log is not proof of safety. What the sources give you is a set of signals to correlate, starting from 17 October, not the 21st.
Signals named by the sources
- Wiz: unusual multipart requests followed by memory-limit errors or repeated HTTP 500 responses, unexpectedly large or malformed PHPSESSID response cookies, and unexplained PHP worker churn.
- Amazon: POST requests with the PHP_SESSION_UPLOAD_PROGRESS string in form uploads. That string lives in the request body, so only a WAF or body logging will see it.
- PHP advisory: ‘Maximum execution time exceeded’, parse, compile and uncaught errors, warnings or deprecations repeated before your scripts run, and diagnostics during cleanup.
- Amazon’s IPs: six addresses on shared anonymization infrastructure. Amazon says to investigate hits rather than just block them.
Read-only log hunting (Debian/Ubuntu paths; adjust for RHEL)
Everything below only reads logs. zgrep and zcat -f read rotated .gz files too.
# 1. Fatal errors that act as triggers
sudo zgrep -hE 'Allowed memory size of [0-9]+ bytes exhausted|Maximum execution time of [0-9]+ seconds? exceeded' \
/var/log/php*-fpm.log* /var/log/apache2/error.log* /var/log/nginx/error.log* 2>/dev/null | tail -50
# 2. Worker churn: FPM children dying, Apache children crashing
sudo zgrep -hE 'exited on signal|exited with code [1-9]' /var/log/php*-fpm.log* | tail -50
sudo zgrep -h 'exit signal' /var/log/apache2/error.log* | tail -20
# 3. Bursts of 500s on POST, by client IP and minute (combined log format)
sudo zcat -f /var/log/nginx/access.log* | \
awk '$6=="\"POST" && $9==500 {split($4,t,":"); print $1, t[1]":"t[2]":"t[3]}' | \
sort | uniq -c | sort -rn | head -20
# 4. The IPs Amazon published (shared infrastructure: investigate, don't just block)
sudo zgrep -hE '^(103\.216\.220\.92|31\.223\.184\.166|37\.19\.200\.5|134\.209\.159\.64|103\.114\.163\.188|95\.217\.98\.37) ' \
/var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/nullLog what the default formats miss, for the next few weeks
The combined format records neither Content-Type nor response cookies. These formats add both. Set-Cookie values are live session IDs: restrict access to this log and delete it when you’re done.
# nginx (inside http {})
log_format php2shell '$remote_addr [$time_local] "$request" $status '
'$request_length "$content_type" "$sent_http_set_cookie"';
access_log /var/log/nginx/php2shell.log php2shell;
# Apache (needs mod_logio for %I)
LogFormat "%h %t \"%r\" %>s %I \"%{Content-Type}i\" \"%{Set-Cookie}o\"" php2shell
CustomLog ${APACHE_LOG_DIR}/php2shell.log php2shell
# PHPSESSID values far longer than your session.sid_length (default 32)
grep -ohE 'PHPSESSID=[^;" ]+' /var/log/nginx/php2shell.log | awk 'length($0) > 80' | sort | uniq -c | headIf you find a hit
Treat the host as compromised until proven otherwise. The code runs with the web worker’s privileges, so assume anything that user can read (.env files, database credentials, API keys) is exposed. Look for unexpected processes and modified files under the web root, as Amazon recommends, rotate those secrets from a clean machine, and rebuild rather than clean in place when you can.
6. Stuck on PHP 8.1 or Older
php.net ships no new 8.1, 8.0 or 7.4 releases, but ‘no official release’ is not the same as ‘no fix’. Here is what exists, in the order I’d reach for it.
- 1. Packaged backports: Ubuntu 22.04 patched its php8.1 (8.1.2-1ubuntu2.28). Surý ships 8.1.34-9, 1:8.0.30-25 and 1:7.4.33-31, and the 8.1 changelog reads ‘Backported from 8.2.35 [CVE-2026-109618, CVE-2026-109619]’. php -v says the same before and after, so check the revision with dpkg -l.
- 2. Source backports: the PHP security team published minimal backports for 7.4, 8.0 and 8.1 for people who build from source or have no LTS vendor.
- 3. Docker: the official php:8.1 tags were last updated in December 2025. There is no patched official 8.1 image: build on a distro package that carries the backport, or move up.
- 4. Mitigate and keep it: AWS’s bulletin tells end-of-life branches to apply the interim CVE-2026-109619 controls and restart workers. On these branches step 3 isn’t temporary.
- 5. Upgrade to 8.4 or 8.5, not 8.2: 8.2 security support ends on 31 December 2026, so it buys you two months. 8.3 runs to 31 December 2027, 8.4 to 2028 and 8.5 to 2029.
7. Common Mistakes I Would Check For
Each of these leaves a server vulnerable while the dashboard says ‘patched’.
- ✗ Trusting php -v on the CLI: the CLI, FPM and mod_php are separate packages and can be on different versions. Check php-fpmX.Y -v and the module Apache loads.
- ✗ Reading distro versions as upstream versions: Ubuntu 24.04’s patched PHP still says 8.3.6, and Surý’s patched 8.1 still says 8.1.34. Judge by the package revision or the vendor’s notice.
- ✗ Upgrading without restarting: a new package on disk does nothing for a master process still running the old binary. The /proc check in step 1 finds them, queue workers included.
- ✗ Restarting a container instead of rebuilding: or running docker run php:8.4-fpm against an old image cached locally. Pull, rebuild with --no-cache, recreate.
- ✗ Setting mitigations where PHP reads them too late: ini_set(), .user.ini or php_value instead of php_admin_value in the pool or server config.
- ✗ Treating the WAF as the fix: every vendor that shipped rules calls them a stopgap, and they do nothing for traffic that reaches the origin directly.
- ✗ Starting the investigation on 21 October: Amazon saw the first attempt on the 17th.
8. What Is Confirmed and What Is Not (Checked 26 October 2026)
‘Confirmed’ means a primary source (php.net, a GHSA advisory, a distro or vendor bulletin, a package index) plus at least one more. Everything else is worded ‘according to’.
Fixed versions and scope
php.net, both GHSA advisories, AWS, Debian, Ubuntu, Remi and Surý’s index agree: 8.5.12, 8.4.27, 8.3.36 and 8.2.35, with every earlier release of those branches affected. Wiz says nearly every PHP version back to 5.4 is hit by at least one of the two.
Exploitation
Amazon reports a pre-disclosure attempt on 17 October and broad exploitation since; Cloudflare, watchTowr and others reported attempts around disclosure. CISA said at publication it had not observed exploitation. I found no public, confirmed successful compromise, which is absence of evidence, not evidence of absence.
Severity
PHP scores both CVSS v4.0 9.2. Red Hat rates CVE-2026-109618 Important (CVSS 3.1 8.1), arguing default RHEL setups use FPM and are harder to exploit. Patch regardless.
Log indicators
The PHPSESSID and HTTP 500 signals come from Wiz’s write-up, not the PHP advisories; the upload-progress string comes from Amazon. Treat all of them as hunting leads, not signatures.
Who found it, and the AI angle
Wiz says it used Wiz Atlas, Gemini 4 Argon and GPT-5.6 Sol; the GHSA credits four reporters, and Reuters reports Calif found the flaws with a language model on 1 August. ‘Several teams, AI-assisted’ is the accurate summary.
NSA wording and cPanel status
nsa.gov refused my fetch, so the NSA’s ‘update or take systems offline’ guidance is as reported by TechCrunch, Defense One and AFP. The cPanel EasyApache fix rests on Tanium’s report alone.
Golden rule
Patch the binary that serves HTTP, prove it with the package revision and the /proc check, restart every worker, and only then believe the version number.
Conclusion
PHP2Shell is the rare bug where your application barely matters: on mod_php the attack can fire before any of your code runs, and updating WordPress or Laravel changes nothing. The work is operational: find every PHP that answers HTTP, patch it the way your environment demands, and prove the running process is the new one.
If you can patch today, do it and keep upload progress off until the next release closes CVE-2026-115560. If you can’t, layer the php.net mitigations and a WAF, hunt from 17 October, and put the move off 8.1 and 8.2 on this quarter’s plan.
This week in one screen
Check
- • php-fpmX.Y -v, not php -v
- • Package revision for backports
- • /proc maps for (deleted)
Patch
- • Packages or a rebuilt image
- • Restart FPM, Apache, workers
- • 8.1 and older: backport or move
Watch
- • Upload progress off (115560)
- • Logs from 17 October
- • WAF as a bridge only
Sources
- php.net — News archive 2026 (21 Oct advisory, 23 Oct CVE-2026-115560, 26 Oct Windows builds)
- GitHub — GHSA-w8hw-w9fx-j79w, RCE via OOM corruption (CVE-2026-109618)
- GitHub — GHSA-6wmf-4rv5-p3rp, RCE via stale global state (CVE-2026-109619)
- Wiz Research — PHP2Shell: AI uncovers critical RCE vulnerabilities
- AWS Security Blog — Amazon threat intelligence identifies PHP2Shell exploitation prior to public disclosure
- AWS Security Bulletin 2026-143-AWS — PHP web runtimes
- Red Hat — RHSB-2026-013
- Ubuntu — USN-8948-1
- Debian security tracker — CVE-2026-109618
- Laravel Forge — PHP security advisory (CVE-2026-109618, CVE-2026-109619)
- Remi’s RPM repository — PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12
- FrankenPHP — v1.13.2 security release
- Docker Hub — official php image tags
- php.net — Supported versions
- TechCrunch — The internet is having a very bad cybersecurity day



