On 21 October 2026 the PHP project fixed two critical flaws in PHP itself that let an attacker with no account run commands on the server. If you are not on 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or your distribution's package has not reached its fixed version, update today, restart every PHP worker, and review your logs from 17 October. WAF rules and interim settings only buy time.

The flaws are not in a plugin, theme or framework. They are in the part of PHP that reads every web request before your code sees it, so an up-to-date WordPress or Laravel, or well-written code, does not protect you on its own.

Note: The status in this article was last checked on 22 October 2026. Exploitation attempts are reported by several independent sources, but no confirmed compromise of a real system has been reported, and neither CVE is in CISA's Known Exploited Vulnerabilities (KEV) catalogue. Any change will be recorded here with its date.

At a glance

Topic Status
What Two flaws in PHP's core request handling: CVE-2026-109618 (corruption on out-of-memory) and CVE-2026-109619 (stale global state)
Severity 9.2 on CVSS 4.0, Critical, for each. The "10.0" that circulated on the first day is wrong
Impact Command execution as the web-server user, with no login; and memory disclosure, including passwords, tokens and API keys from other requests
Worst setup Apache with mod_php: the attack fires before the first line of application code runs
Fixed in 8.5.12, 8.4.27, 8.3.36 and 8.2.35
8.1 and older No release. The PHP security team published minimal source back-ports for 7.4, 8.0 and 8.1
Exploitation Attempts since 17 October; proof-of-concept code is public; no confirmed compromise reported
The only complete fix Update to the exact release and restart every PHP worker

What happened

The root cause goes back to 2024. While fixing an issue from a Quarkslab security audit, a PHP core developer found the first signs of the out-of-memory problem. No practical attack path was found, and the fix stalled for months; the PHP Foundation now calls the delay "a structural failure". In August 2026 three independent teams, Calif, OpenAI and Wiz, reported working code-execution paths within two weeks of each other, and the fix became the top priority.

From a 2024 audit to attacks before the patch Times in UTC 2024 First signs found while fixing a Quarkslab audit issue; the fix stalled for months 11 Aug 2026 Calif and OpenAI report working RCE paths; Wiz follows on 24 Aug 17 Oct First exploitation attempt in AWS honeypots, four days before the patch 20 Oct, ~15:00 CVE IDs leak, with a wrong score of 10 20 Oct, ~20:00 A proof-of-concept video is published by mistake 21 Oct, 03:02 Cloudflare switches on WAF rules by default 21 Oct, 14:00 PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 released 21–22 Oct Attempts at scale; no confirmed compromise of a real system reported
Exploitation attempts began four days before the fix was released.

Example: the 20 October chain. The release was planned for Thursday 22 October. Around 15:00 UTC on Tuesday 20 October the two CVE IDs spread on social media with a wrong score of 10.0, still without technical details. PHP brought the release forward by a day rather than releasing at once, because distributions were still packaging the fix. That evening one research team published a proof-of-concept video by mistake, and the first GitHub repositories claiming a working exploit appeared. At 07:41 UTC on 21 October a vendor published fixed images hours ahead of the embargo. The fixed releases went out at 14:00 UTC. Before any of this, AWS had recorded an exploitation attempt in its honeypots on 17 October, and does not know where the attacker got the details.

What to do today

If you read only one section, read this table. The order matters: inventory, patch, restart, then look back.

When Action Owner
Next few hours List every service that exposes PHP to the internet, including containers, shared hosting and vendor-installed systems Head of engineering or IT
Today Update to the exact release, or to your distribution's fixed package, and fully restart every worker Operations
Until patched The interim settings below, WAF rules in block mode, and no direct access to the origin server Operations and security
Within 72 hours Review logs and worker behaviour from 17 October, not from the day you patched Security team
If a server was exposed and unpatched for a while Rotate the database passwords, API keys and tokens that pass through it Security team
This week An upgrade plan for 8.1 and older, and for 8.2, which loses security support on 31 December 2026 Head of engineering or IT

Ask your team or your hosting provider:

  1. Which exact PHP release runs on each internet-facing service?
  2. Did you confirm the fix from the package version and the distribution's advisory, or only from php -v?
  3. Were the PHP-FPM or Apache workers restarted after the install?
  4. Have the logs been reviewed from 17 October, and what did they show?
  5. Can the origin server be reached from the internet without passing the CDN and WAF?
  6. What is the plan for services on 8.1 or older?

Example: a WooCommerce shop on shared hosting. The host announces that "PHP on all plans has been upgraded to 8.2 or later". That does not answer the question: 8.4.26 is later than 8.2 and still vulnerable. The first three questions above settle it. On shared hosting, ask support for the exact PHP package version and the advisory that confirms the fix, because some patched control-panel packages still report the old version number. A notice that "dangerous functions have been disabled" does not replace the patch either: the first flaw fires before any function in your code is called.

If you cannot produce a complete list of the services that expose PHP to the internet, that is where to start; attack surface management exists for exactly that outside view.

Who is at risk

Any service that answers web requests with a vulnerable PHP. Wiz achieved unauthenticated code execution on the official WordPress, Drupal and Joomla images and says even a simple "Hello World" application on an affected version can be vulnerable. Calif reproduced it in a lab on Magento, Laravel, Symfony, phpMyAdmin, Nextcloud and several other applications.

The footprint is large. According to W3Techs on 22 October 2026, PHP is the server-side language of 69.3% of websites whose language is known, and about 48% of PHP sites run 8.1 or older, which get no release.

The risk depends on how PHP is attached to the web server. The table summarises the PHP team's own assessment in its two official advisories:

Setup CVE-2026-109618 CVE-2026-109619
Apache with mod_php Highest risk; code execution before application code demonstrated Code execution demonstrated
PHP-FPM (behind Nginx or Apache) At risk; PHP's two official sources disagree on whether a full exploit was shown Session path validated; depends on application behaviour
FrankenPHP Likely susceptible; not validated No path found in the default configuration, which does not make it immune
LiteSpeed (LSAPI) Likely; not validated Conditional
php-cgi Listed as at risk; no separate analysis published Listed as at risk
Command line (CLI) Out of scope Out of scope

On FPM, be precise: the official advisory for the first flaw says no complete FPM exploit was demonstrated and that FPM is susceptible by source analysis, while the PHP Foundation says code execution "was also confirmed on PHP-FPM through application-level code paths". The practical answer is the same: Nginx with FPM must be patched too.

Example. The usual Apache and PHP install on Debian and Ubuntu, with the libapache2-mod-php package, is mod_php: the highest-risk setup, even if php-fpm is also installed and sitting idle. Apache handing requests to PHP-FPM through mod_proxy_fcgi, on the other hand, is an FPM setup. To tell which you have, list the modules Apache has loaded; the command is in the patching section.

The first flaw: running out of memory at the wrong moment (CVE-2026-109618)

In plain terms. PHP gives each request a memory limit and stops a request that exceeds it on the spot. The flaw is that the stop can land halfway through PHP filling in its own bookkeeping, like a clerk who writes "three boxes received" in the ledger and is called away before the third box is on the shelf. The cleanup crew later trusts the ledger and reaches for a box that was never there. An attacker shapes a request so that memory runs out at exactly that moment, and cleanup then works on data the attacker has shaped.

For engineers. Vulnerable versions handle a failed memory allocation with longjmp(), jumping out of whatever was running. In some paths request memory is reachable before it is fully initialised, and request shutdown then reads it. The official advisory makes three points most summaries miss:

  • Any failed allocation can be the trigger, not only hitting memory_limit, and the allocation that fails need not be related to the memory that gets corrupted.
  • The structure that is corrupted is the request-variable table, such as $_POST, which PHP builds while parsing the request body; not session structures.
  • On mod_php, shutdown runs even when request start-up has failed, so all of this happens before application code runs and a login page or careful code does not stop it.

Datadog and Calif locate the exact path in a Zend engine hash-table helper that increments the table's counters before allocating the copy of a new key; if that allocation fails, a bucket is counted that was never filled. The fix removes longjmp() for out-of-memory: PHP now stops at the next safe point, and terminates the process at once above a higher threshold.

The attack lands before your code runs CVE-2026-109618 on Apache with mod_php Before any application code runs 1. A crafted form request, no login 2. PHP files the body into the $_POST table 3. A memory allocation fails mid-entry; PHP jumps out 4. Cleanup trusts the half-written entry 5. A command runs as www-data; the response can be 200 WAF: body and field limits, partial Low post_max_size: reduces the risk Patch: removes the cause EDR: spots a shell spawned by PHP
Only the patch removes the cause; the other controls reduce the risk or detect the attack.

Example: a 200 response is not proof of a harmless request. In Datadog's lab an ordinary form, not a file upload, carried one nested field name of about 3.5 MB. The response came back after about three seconds with HTTP 200 and the out-of-memory error in its body. In the same request a command ran as www-data, and the worker stayed alive. Failed attempts tend to show up as 500 errors and crashed workers; a successful one may show neither. This is also why blocking only multipart requests is not enough.

The second flaw: a pointer left over from the previous request (CVE-2026-109619)

In plain terms. A PHP worker serves many requests in a row, like a hotel room cleaned between guests. In this flaw, when the previous guest leaves abruptly, with an error or a timeout, part of the cleaning is skipped. A note stays behind saying "your valuables are in drawer three", but drawer three has since been given to someone else. The next request follows the note. If the attacker sends both requests and both reach the same worker, they can decide what is in that drawer.

For engineers. PHP keeps some per-worker state global: error state, session, object and extension state. That state temporarily points into the current request's memory. The official advisory says that when a request is interrupted, by a parse error, an uncaught error, a failed require, the execution time limit or out-of-memory, or when a late warning during cleanup repopulates that state, the pointer survives after the memory is freed. A later request on the same worker may read it before it is initialised. Two paths are demonstrated:

  • Fatal-error backtraces in PHP 8.5. The fatal_error_backtraces setting exists from 8.5 and is on by default. It is the basis of the demonstrated code execution on mod_php, and Wiz used it against Drupal.
  • Session upload progress. On by default, validated on both mod_php and FPM, and it does not need the application to call session_start() at all.

PHP states plainly that changing error_reporting, using @, or turning off display_errors and log_errors does not protect you. More workers lower the success rate of each attempt but do not remove the condition. Wiz also reports an OPcache path that PHP's official advisories do not mention.

A stale pointer, carried from one request to the next CVE-2026-109619 One PHP worker, two requests in a row Request A (attacker) fatal error, timeout or out of memory Global state still points into A's memory memory freed, pointer kept Request B (attacker) on the same worker upload progress, an INI warning or the 8.5 backtrace Memory leaks into the PHPSESSID response cookie, or code runs Patch: state is reset before reuse session.upload_progress.enabled=0 fatal_error_backtraces=0 (8.5 only) pm.max_requests=1 (costly)
The two flaws chain: the first flaw's out-of-memory is one way to create the stale state.

Example: a cookie the site never set. A site that does not use sessions at all suddenly returns a very long, garbled PHPSESSID cookie. According to Wiz's analysis, that is reclaimed worker memory travelling back to the attacker, and it can hold passwords, authentication tokens, API keys or certificates from other requests. This leak does not need code execution, so a server that sat unpatched on the internet may have lost secrets even if nobody ran a command on it.

Patching correctly, and the version-number trap

The fixed releases are 8.5.12, 8.4.27, 8.3.36 and 8.2.35; anything lower on the same branch is vulnerable. But most servers do not get PHP from php.net. They get it from a Linux distribution or a hosting panel, which back-port the fix without changing the version number.

Are we really patched? Where does PHP answer web requests? servers, containers, hosting panels Where does that PHP come from? php.net build or official Docker image At least 8.5.12, 8.4.27, 8.3.36 or 8.2.35? Linux distro or panel package Is the package at your distro's fixed version? per the distro advisory or changelog; php -v does not decide 8.1 or older No release: source back-port or an LTS vendor, plus an upgrade plan No Patch today; until then, interim settings and WAF in block mode Yes Were the workers restarted after the install? Review logs from 17 October Exposed and unpatched for a while? Rotate passwords and keys
For distribution or panel PHP, the package version decides, not php -v.
Where PHP comes from Patched package What php -v shows
php.net and the official Docker image 8.5.12, 8.4.27, 8.3.36, 8.2.35 The same number
Ubuntu 24.04 8.3.6-0ubuntu0.24.04.13 8.3.6
Ubuntu 22.04 8.1.2-1ubuntu2.28 8.1.2
Debian 12 8.2.35-1~deb12u1 8.2.35
Debian 13 8.4.27-1~deb13u1 8.4.27
AlmaLinux 9 (php:8.3 module) 8.3.36, or the interim 8.3.33-1 (alma.1) build 8.3.36 or 8.3.33
cPanel, DirectAdmin and Plesk The panel's patched package Sometimes the old number; check the changelog

These versions are from the Ubuntu, Debian and AlmaLinux advisories as of 22 October. Red Hat had not shipped fixes for every stream by then; follow RHSB-2026-013. The volunteer-run remirepo did not update on release day, and PHP advised switching to distribution packages or building from source.

The rule is simple: for distribution or panel PHP, compare the package version with that distribution's security advisory. The changelog usually names both CVEs and is a second check, but not always: in our test on AlmaLinux 9 the patched 8.3.36 package's changelog said only "rebase to 8.3.36", with no CVE ID. Slim container images drop changelogs altogether.

To find the PHP that actually answers web requests, not the command-line one:

# Which processes serve PHP
ps -eo user,pid,args | grep -E '[p]hp-fpm|[a]pache2|[h]ttpd'

# Apache: built-in PHP (php_module) or FPM through proxy_fcgi? (RHEL family: httpd -M)
apache2ctl -M 2>/dev/null | grep -Ei 'php|proxy_fcgi'

# Debian / Ubuntu: compare the package version with your distribution's advisory
dpkg-query -W 'php*-fpm' 'php*-cli' 'libapache2-mod-php*'
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-fpm/changelog.Debian.gz

# RHEL, AlmaLinux, Rocky, cPanel ea-php: the version first; a rebased package's
# changelog may only say "rebase to 8.3.36" and name no CVE
rpm -q php-fpm
rpm -q --changelog php-fpm | grep -E 'CVE-2026-10961[89]'

# After the restart, no process may still run a replaced PHP file (expect no output)
grep -lE '(php|libphp).*\(deleted\)' /proc/[0-9]*/maps 2>/dev/null

# Containers: the official php image reports the real upstream version
docker ps --format '{{.Names}}  {{.Image}}'

After installing, fully restart every worker, not just a reload: one that started before the install keeps running the old code. On Debian and Ubuntu that is systemctl restart php8.3-fpm apache2; on the RHEL family, systemctl restart php-fpm httpd. If Apache runs mod_php, restarting php-fpm alone does not patch the site. After the restart, the last check in the block above should print nothing. For containers a new tag is not enough; pull the image again and redeploy. The official Docker images have no patched tags for 8.1 and older.

Example: a server that says 8.3.6. We ran this in a clean Ubuntu 24.04 container. php -v reports 8.3.6, which looks far below 8.3.36. dpkg-query shows the package as 8.3.6-0ubuntu0.24.04.13, the version Ubuntu's advisory lists as fixed, and the changelog names both CVEs, so the package is patched. But until Apache and php-fpm were restarted, the last check in the block above listed both the apache2 and php-fpm8.3 processes: the old code was still in memory. After the restart the output was empty.

If you cannot patch today

PHP is explicit: these settings close specific attack paths but do not make an installation safe, and no generic setting fully covers both flaws. Apply each one in the php.ini the web server loads, the FPM pool or the server configuration, then restart every worker; ini_set() and .user.ini act too late. On Debian and Ubuntu, FPM reads /etc/php/8.3/fpm/php.ini and PHP inside Apache reads /etc/php/8.3/apache2/php.ini, while php -i shows only the command-line file.

Setting For What it blocks What it misses Cost
session.upload_progress.enabled = 0 CVE-2026-109619 The demonstrated session paths Other variants Upload progress bars stop working
fatal_error_backtraces = 0 (8.5 only) CVE-2026-109619 The backtrace path Other paths Less debugging detail
A low post_max_size: 8M without uploads, 32M with CVE-2026-109618 Some request-body paths Other out-of-memory paths Large uploads are refused
memory_limit = -1, enforced with php_admin_value CVE-2026-109618 PHP's primary configuration mitigation Other failed allocations Only together with a cgroup or container memory limit per worker
Front-end limits: body size, field and part count, name length, nesting depth CVE-2026-109618 Some crafted requests Mutated payloads May reject legitimate requests
pm.max_requests = 1 CVE-2026-109619 The "same worker" precondition A heavy performance cost
; the php.ini the web server loads (fpm/ or apache2/, not cli/), then restart
session.upload_progress.enabled = 0
; PHP 8.5 only
fatal_error_backtraces = 0
; 8M without uploads, 32M with uploads; keep upload_max_filesize below it
post_max_size = 8M
upload_max_filesize = 4M

Note: Never limit memory with RLIMIT_AS or RLIMIT_DATA. PHP warns that they produce exactly the kind of allocation failure that triggers the first flaw. Set the memory ceiling with cgroups or container limits, so that only the affected worker is killed.

Example: a shop that takes no uploads. A shop whose forms never accept files sets post_max_size to 8M and session.upload_progress.enabled to 0, blocks multipart at the front end, restarts php-fpm, and installs the fix that night. These settings buy hours, not safety.

WAF: a supporting layer, not the fix

Several providers have shipped dedicated rules. Cloudflare turned its rules on by default for free and paid plans from 03:02 UTC on 21 October and inspects the request and the response together; Akamai published rule 3000991; Imperva, Sucuri and Imunify360 shipped virtual patches. AWS has no dedicated managed rule and has published guidance for custom rules instead. Cloudflare also reports attackers mutating their payloads to slip past the rules.

If your site sits behind a CDN or WAF, ask whether a rule for both CVEs is active and in block mode, and make sure the origin cannot be reached around it. To measure what your WAF actually catches, test its effectiveness class by class.

Example: body inspection limits. AWS WAF inspects only the first 8 to 64 KB of a request body, depending on the service. The multi-megabyte field name from Datadog's lab is far outside that window; unless oversize requests are set to block, the WAF never sees the dangerous part.

Were we hit?

AWS advises starting the review from at least 17 October, not from the day you patched. There is no single signature, and these attacks leave little behind, so look for behaviour rather than status codes.

Data source What to look for
PHP error log Out-of-memory fatals "in Unknown on line 0", meaning before any script ran
Apache error log Child crashes (AH00052 with a segmentation fault) after unusual POSTs
PHP-FPM log Workers exiting on signal 11 (SIGSEGV), or repeated restarts
Access and WAF logs POSTs with very large bodies, very long field names, many multipart parts, or a PHP_SESSION_UPLOAD_PROGRESS field
HTTP responses Very long or garbled PHPSESSID cookies
Process monitoring and EDR A shell started by php-fpm or Apache that connects outward
File monitoring New PHP files in writable directories, new cron jobs or accounts

Example: two lines that matter together. These two lines are illustrative, in the real log formats; seen a few seconds apart on an Apache server with mod_php, they deserve a closer look:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 3670048 bytes) in Unknown on line 0
[core:notice] [pid 812] AH00052: child pid 4127 exit signal Segmentation fault (11)

"Unknown on line 0" means memory ran out before any script ran. None of these signs is proof on its own, and their absence does not prove a server is clean. The IP addresses AWS published include shared anonymisation infrastructure; AWS itself says to investigate them, not block them.

If you find something, preserve logs, configuration and suspicious files before changing anything, isolate the server, rotate the secrets that pass through it, and rebuild it.

The fixes from the last three months come with it

The 21 October releases include every earlier fix on the same branch. The three previous security releases, on 2–3 July, 30 July and 24 September, carried 17 advisories that most coverage skipped. The ones that matter most for typical websites:

Release ID Severity Component Impact
24 Sep CVE-2026-91765 High SOAP server Unauthenticated denial of service through a deeply nested SOAP request
24 Sep CVE-2026-91766 Medium http:// stream wrapper Authorization, Cookie and Proxy-Authorization headers forwarded to a cross-origin redirect target
24 Sep CVE-2026-91768 Medium PHP-FPM IPv6 allow-list bypass
24 Sep CVE-2026-91769 Medium OpenSSL in PHP Falls back to the certificate CN after a SAN mismatch
30 Jul CVE-2026-17543 High pgsql extension SQL injection in pg_insert, pg_update, pg_select and pg_delete
30 Jul CVE-2026-17544 High bcmath Out-of-bounds write in bccomp(), 8.4 and 8.5 only

Example: one allowed address became a range. In CVE-2026-91768, PHP-FPM compared only 12 of the 16 bytes of an IPv6 address when checking listen.allowed_clients. Every allowed address was in effect a /96 range, and any machine in it could talk to FPM directly.

These fixes reached supported branches only. The last 8.1 release was 8.1.34, on 18 December 2025.

What this says about patch deadlines

This section is our view. A weakness that was half-known in 2024 became working code execution in the hands of three independent teams within two weeks in August 2026. Wiz says it used AI models to find vulnerabilities and build the exploit chain; the PHP Foundation says AI helps it validate and group reports, and that a person makes every call. After the CVE IDs leaked, repositories claiming exploit code appeared within hours, although PHP found none of them functional at release time.

The conclusion for a manager is plain: for internet-facing services, a 30-day deadline for a critical patch is no longer realistic. What helps on a day like this is built in advance: an up-to-date list of services, a way to install patches even when upstream repositories are slow or unreachable, and logs that reach back several days.

Common questions

Our WordPress or Laravel is up to date. Are we still at risk? Yes, if PHP itself is not patched. The flaw is in PHP, and updating the CMS or framework does not fix it.

Our site is behind a CDN and WAF. Is that enough? No. Attackers mutate payloads to slip past rules, some WAFs inspect only the start of the body, and the origin can sometimes be reached without passing the WAF. Treat the WAF as a supporting layer and the patch as the control.

php -v says 8.3.6. Are we vulnerable? Not necessarily. Ubuntu back-ported the fix without changing the version number. Compare the package version with your distribution's security advisory, and make sure the workers were fully restarted after the install.

We still run PHP 7.4 or 8.1. What now? No release is coming. Apply the source back-ports the PHP security team published for 7.4, 8.0 and 8.1, or get them from a long-term-support vendor; until then use the interim settings and isolate the server, and write the upgrade plan this week.

We are on shared hosting with no server access. What can we do? Ask the host for the exact PHP release, when the workers were restarted, and the result of the log review from 17 October. "8.2 or later" does not answer any of these.

Sources