On October 21, 2026, the PHP project released PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35 as security releases. Two vulnerabilities, CVE-2026-109618 and CVE-2026-109619, can lead to unauthenticated remote code execution. The PHP advisory is unusually direct: there are no complete mitigations, and updating is the only safe choice.
The uncomfortable part is where the bugs live. They are not in WordPress, Laravel, Symfony, or your own application code. They are in the PHP engine's request lifecycle, before your application gets a chance to run. Strong authentication and careful input validation matter, but they do not repair memory corruption in the runtime that parses the request.
What PHP fixed: two failures in request lifetime management
The two CVEs are different bugs with the same theme. A request ends abnormally, PHP leaves internal state partially initialized or pointing at freed memory, and a later request or the shutdown path uses that state.
| Item | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| Official name | RCE via OOM corruption | RCE via stale global state |
| Core trigger | Memory limit reached during multipart request handling | Request-owned global state survives after its backing memory is freed |
| Failure point | longjmp() aborts the request while request memory is only partially initialized |
The next request on the same worker reads the old state before normal initialization replaces it |
| Demonstrated impact | Unauthenticated RCE, worker memory disclosure | Heap use-after-free, memory disclosure, RCE |
| CVSS v4.0 | 9.2 Critical | 9.2 Critical |
| Important condition | On mod_php with default limits, the attack can trigger before application code runs |
The producer and consumer requests must reach the same worker |
Both advisories use the vector AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N. The attack is reachable over the network, needs no privileges or user interaction, and has high impact on confidentiality, integrity, and availability. It also has high attack complexity and specific attack requirements present.
That combination is easy to misread. High complexity does not mean low priority. It means the attacker has to arrange particular request shapes, worker reuse, or allocator conditions. When those conditions line up, the result is code execution as the web worker. Even when full RCE is not achieved, memory disclosure can expose credentials, session material, and keys from the PHP process.
Why application-layer defenses cannot compensate
Before your controller or framework router runs, PHP has already parsed multipart input, initialized request data, and possibly handled session upload progress. If an allocation fails in that window, PHP exits the request through longjmp(). The cleanup path can then treat partially initialized request memory as valid. The second bug follows the same pattern across requests: request-owned global state is not reset before the request heap is freed, and the next request on that worker can consume stale state.
Request A: multipart parsing or upload-progress handling
→ memory limit reached
→ longjmp aborts the request
→ request memory is only partially initialized
→ shutdown reads the invalid state
→ Request B on the same worker reuses it
Wiz Research demonstrated the chain against the latest WordPress, Drupal, and Joomla container images at the time of testing. The CMSs were targets, not the root cause. Wiz notes that even a simple "Hello World" application on a vulnerable PHP build can be affected because the primitive is in the engine.
This is why "we have authentication," "we have a WAF," or "the application validates input" is not a sufficient answer. A WAF can reduce specific request shapes, and proxy limits can make some paths harder. Neither repairs a memory-safety bug in the runtime. Application-layer controls are still useful, but they are not a substitute for the patch.
Who is exposed: versions and SAPIs
Official fixes exist for PHP 8.2 through 8.5. PHP 8.1 and older no longer receive upstream support. Some distributions and LTS vendors provide backports, and the PHP security team published minimal source backports for 7.4, 8.0, and 8.1 for people who build from source.
| PHP branch | Fixed version | Note |
|---|---|---|
| PHP 8.5 | 8.5.12 | Current stable branch |
| PHP 8.4 | 8.4.27 | Security release |
| PHP 8.3 | 8.3.36 | Security release |
| PHP 8.2 | 8.2.35 | Reaches end of life on December 31, 2026 |
| PHP 8.1 and older | No regular upstream release | Check vendor backports or upgrade |
Wiz says nearly every PHP version released in the last decade is affected by at least one of the bugs, going back to PHP 5.4. That is Wiz's assessment, not a promise that every old build has a vendor-supported fix. The practical question for an operator is not "is our PHP too old to matter?" It is "did our vendor backport the fix, and are we actually running it?"
The SAPI matters too. The PHP advisory names PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP, and LiteSpeed as exposed. It considers mod_php the highest risk because a demonstrated unauthenticated request can reach the vulnerable path before any application code runs.
| Runtime | Exposure | What to check |
|---|---|---|
| Apache with mod_php | Highest risk | Pre-application request startup can trigger the path |
| PHP-FPM | Affected | The session lifecycle RCE was validated on both mod_php and FPM |
| php-cgi, FrankenPHP, LiteSpeed | Named in the official advisory | Check the actual web SAPI, not only the CLI binary |
| CLI-only batch jobs | Different request path | Still inventory the PHP binary and package version |
"Unauthenticated" does not mean "no network access." The attacker still needs to reach a PHP endpoint and satisfy the request conditions. But no application login is required. An internal service is not automatically safe, and an internet-facing PHP endpoint deserves immediate attention.
Patch and verify
The first rule is simple: update PHP and restart every worker. Updating a package while an old FPM master or Apache worker keeps serving requests can leave the patched binary unused.
- Identify the runtime that actually handles web requests. A
composer.jsonplatform requirement is not an inventory. - Patch through the same supply chain that provides the runtime: distribution package, official source build, or container base image.
- Restart FPM masters, Apache, and container instances. Clearing opcache alone is not a restart.
- Re-check the version through the web SAPI. CLI
php -vand the FPM package can differ. - Treat WAF or CDN rules as temporary risk reduction, not as the fix.
Cloudflare says it deployed default WAF protections before disclosure. That is useful risk reduction, not a substitute for the patch.
A minimal deployment gate can catch an unpatched CLI binary before release. This example was not executed for this article and should be adapted to your package layout.
<?php
// Not executed: a minimal CLI version gate for CI or deployment
$minimum = [
'8.2' => 80235,
'8.3' => 80336,
'8.4' => 80427,
'8.5' => 80512,
];
$branch = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
$required = $minimum[$branch] ?? null;
if ($required === null || PHP_VERSION_ID < $required) {
fwrite(STDERR, 'Unpatched PHP: ' . PHP_VERSION . PHP_EOL);
exit(1);
}
fwrite(STDOUT, 'PHP ' . PHP_VERSION . ' meets the minimum patch level.' . PHP_EOL);
This checks the CLI only. It does not prove that the FPM pool, the web SAPI, or the container image is patched. Those need separate checks, and the workers need a real restart.
If you cannot patch immediately
The PHP advisory provides temporary mitigations, but explicitly says they do not make an installation safe. They reduce exposure to specific paths.
| Vulnerability | Temporary control | What it buys | Limit |
|---|---|---|---|
| CVE-2026-109618 | Set memory_limit=-1 through php_admin_value in the FPM pool or Apache config |
Removes the controllable PHP memory-limit failure | An underlying allocation failure can still reach the vulnerable path |
| CVE-2026-109618 | Set post_max_size=8M without uploads, or 32M with uploads; keep upload_max_filesize below it |
Reduces multipart size and parsing pressure | Does not cover every request shape |
| CVE-2026-109618 | Enforce decoded request size, field count, multipart part count, header count, and nesting depth at the proxy or web server | Extends coverage to requests without a usable Content-Length |
May conflict with legitimate traffic |
| CVE-2026-109619 | Set session.upload_progress.enabled=0 in php.ini, the FPM pool, or server config, then restart every worker |
Blocks the confirmed session upload path | Does not cover other stale-state variants |
| CVE-2026-109619 | On PHP 8.5, set fatal_error_backtraces=0 and restart every worker |
Blocks the confirmed fatal-backtrace path | PHP 8.5 only; other paths remain |
memory_limit=-1 is counterintuitive. Removing the PHP memory limit avoids the controllable OOM failure, but it also removes an availability guard. Use a container or cgroup boundary instead. The advisory warns against substituting RLIMIT_AS or RLIMIT_DATA, because those limits can cause the allocation failure that reaches the vulnerable path.
An FPM pool example looks like this. It is also an unexecuted example; choose values that match your upload requirements.
; Not executed: temporary FPM pool settings for a service without uploads
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 4M
php_admin_value[session.upload_progress.enabled] = 0
Do not rely on ini_set() or a per-directory FPM .user.ini. The vulnerable path can run before request parsing, so settings applied later by the application may not help. Hiding diagnostics with error_reporting or display_errors is not a fix either.
Detection signals
Wiz lists a few signals worth investigating before patching: 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. These are clues, not proof. Because the bugs execute below the application layer, normal application logs may contain little context.
If you see these signals, patch first and investigate second. Absence of obvious application errors is not evidence that nothing happened.
What AI actually contributed
It would be inaccurate to summarize this as "AI hacked PHP" or "AI fixed PHP." The published accounts describe a division of labor.
| Actor | Role | Source |
|---|---|---|
| Wiz Research | Found and reported the bugs, demonstrated exploitation against WordPress, Drupal, and Joomla, participated in patch verification | Wiz technical blog |
| Gemini 4 Argon | Wiz credits it with contributing to vulnerability discovery, exploit development, attack detection, and patch validation | Wiz technical blog |
| Calif | Found one of the vulnerabilities using GPT-5.6 Sol | OpenAI's Patch the Planet post |
| OpenAI | Coordinated the Patch the Planet response and provided research and technical support | OpenAI's Patch the Planet post |
| PHP maintainers | Led the fixes and the official release | PHP.net and GitHub advisories |
Wiz says frontier models substantially lowered the barrier to turning a decades-old flaw into a practical exploit. The models helped adapt an exploit across PHP versions, configurations, and memory layouts, and the team could develop and adapt working exploits across multiple applications in hours.
That does not mean a model wrote the patch. PHP maintainers led the fix. The defensive lesson is still stark: if an attacker can adapt one exploit across many versions and configurations in hours, a patch cadence measured in weeks is a liability.
Demonstration is not universal exploitability
Wiz's demonstrations are serious, but they do not mean every PHP server will fall at the same rate. Wiz says exploit portability and reliability depend on the PHP build, extensions, frontend behavior, and allocator layout. More workers and unrelated traffic can increase the number of attempts required. They do not remove the underlying condition.
Wiz's "70% of the Internet" figure is its own estimate of PHP's reach. The direction is not controversial. The exposure of a specific organization still has to be measured with its own runtime inventory.
Conclusion: make the runtime a first-class asset
The lesson is more specific than "keep PHP updated." Many teams track application dependencies in a lockfile but cannot say which PHP binary, SAPI, and configuration serve each production request. In that state, a patch release does not tell them which worker to restart or whether the fix is live.
Three questions matter now. Do you have an inventory of PHP versions and SAPIs per service? Did you actually restart every worker after patching? Can you verify the version and key settings through the web SAPI after deployment?
Application code review cannot close this hole. Patching the runtime and proving that the patched runtime handles requests is the only path to a complete fix.
Further reading
- AI Agent Security: Why You Should Not Run Without Permissions in the Computer-Use Era
- PwnEscape: From an AI Agent Sandbox to the Host Kernel, Through an 18-Year-Old Assumption
- CodeQL 2.27.2: What Security Analysis Catches and What It Misses
- AI Cyber Index: A Vulnerability Agent's Report Card Is Four Numbers
References
- PHP.net: Security advisory — Critical remote code execution vulnerabilities, update now (October 21, 2026)
- PHP.net: PHP 8.5.12 Released! (October 21, 2026)
- GitHub Security Advisory: GHSA-w8hw-w9fx-j79w — RCE via OOM corruption
- GitHub Security Advisory: GHSA-6wmf-4rv5-p3rp — RCE via stale global state
- Wiz Research: PHP2Shell — AI uncovers critical RCE vulnerabilities affecting 70% of the Internet (October 21, 2026)
- The PHP Foundation: Today's PHP Security Release, and How We're Strengthening PHP Security (October 21, 2026)
- OpenAI: Patch the Planet — global response coordination as agents uncover critical vulnerabilities (October 21, 2026)
- Cloudflare: Cloudflare deploys protections against php2shell vulnerability (October 21, 2026)
Go deeper with a course
A runtime patch is only one part of shipping a web service. If you want guided practice taking a website from planning through implementation and deployment, the course walks through the full flow with AI assistance.