PHP2Shell: What the PHP RCE Flaws CVE-2026-109618 and CVE-2026-109619 Mean for Your Attack Surface
Two unauthenticated remote code execution bugs in PHP itself, affecting nearly every version back to 5.4. The details leaked a day early, exploitation attempts began within minutes of the patch, and AI did most of the exploit work. Here is what to patch, what to mitigate, and how to find the PHP you forgot you had.

On 21 October 2026, PHP shipped emergency releases for two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619, together known as PHP2Shell. Both allow an unauthenticated attacker to run code on a PHP server with the privileges of the web worker. Both score 9.2 on CVSS v4.0. Both sit in PHP itself, not in a framework or a plugin, so a plain "Hello World" page on an affected version is exploitable.
The researchers who reported the bugs say frontier AI models did most of the heavy lifting: one person did in about a week what would normally take a team months. The disclosure then went sideways. Details leaked on 20 October, PHP pulled the release forward by a day, and honeypot operators reported exploitation attempts 19 minutes after the scheduled 14:00 UTC release.
If you run anything on PHP, the short version is: update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 now. The longer version, and the part most teams will struggle with, is finding every place PHP is running in the first place.
What PHP2Shell actually is
Both vulnerabilities come from the same weakness: how PHP handles fatal errors, especially out-of-memory errors, in the middle of a request. When a request dies that way, PHP can leave corrupted internal state behind, and the next request on the same worker inherits it.
- CVE-2026-109618 (memory corruption during out-of-memory handling). PHP uses
longjmp()to abort a request when an allocation fails. If that happens while request memory is reachable but not fully initialised, the cleanup that follows reads or branches on invalid data. A crafted multipart request can trigger the failure while appearing to respect the configured limits, for example with no usable Content-Length, unlimited headers per part, empty file controls or deeply nested field names. PHP's advisory says remote code execution was validated over HTTP with default limits against Apache mod_php. - CVE-2026-109619 (use-after-free across requests). PHP keeps global state that temporarily points into request memory. If that state is not reset before the request heap is freed, a later request on the same worker can use the freed memory before normal initialisation clears it. The confirmed paths run through PHP 8.5's fatal error backtrace feature, which is on by default and which PHP calls "the strongest demonstrated case", and through the session upload-progress code, which is validated against both mod_php and PHP-FPM.
The practical consequence, per the advisories and news coverage: an attacker can read worker process memory without first getting code execution, and a working exploit fires from a single unauthenticated request before any application code runs.
Who is affected, and what is fixed
Nearly every PHP version released in the last decade carries at least one of the bugs, back to PHP 5.4. Every server API that serves web requests is in scope: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed. PHP rates mod_php the highest risk, because it runs request shutdown unconditionally, even when request startup has failed, so the out-of-memory path works before any application code runs. PHP-FPM exits the child when startup fails, which limits exposure to that path, but the stale-state bug is confirmed against FPM too.
- Fixed releases: PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Anything below these in each branch is vulnerable. PHP 8.6.0 RC4 also contains the fixes.
- PHP 8.1 and older: no longer receive updates from the PHP project. Given the severity, the security team published minimal source backports for 7.4, 8.0 and 8.1 on dedicated GitHub branches, for people who build from source or have no LTS vendor.
- PHP 5 and 7.0 to 7.3: no fix from the project. Your options are a vendor patch or an upgrade.
- Distributions and LTS vendors received the fix in advance. Check your vendor's packages before building from source. PHP warned that the volunteer-run Remi repository would not have updates on release day.
Note that PHP 8.2 reaches end of life on 31 December 2026. If you are patching 8.2 today, you are buying ten weeks.
The timeline: 63 days in private, 19 minutes in public
The gap between how this vulnerability was handled before and after it became public is the whole lesson.
- 19 August 2026: The researchers find the first bug. Unauthenticated RCE is confirmed against Drupal the next day and WordPress the day after.
- 24 August: Reported to the PHP security team.
- 21 September: PHP acknowledges the reports and starts a coordinated fix. The PHP Foundation later called the delay between competing fixes "a structural failure" of its process.
- 20 October: A post on Hacker News names both CVE IDs and a disclosure date of 22 October. Around 20:00 UTC, one of the research groups accidentally publishes a video of its working proof of concept. PHP posts an advance notice and moves the release to 21 October at 14:00 UTC.
- 21 October, 03:02 UTC: A major CDN switches its firewall rules on for all customers, free plans included, before the patch exists. Its CTO later says the company is already seeing early attacks, and then that attackers are changing payloads to get around the rules.
- 21 October, 14:00 UTC: PHP releases the fixed versions. NIST publishes both CVEs in the National Vulnerability Database at 14:17 UTC.
- 21 October, 14:19 UTC: A global honeypot network reports "active exploitation attempts" against both CVEs, having reported none three hours earlier.
As of 22 October, no public report confirms a successful compromise of a named organisation, and neither CVE is in CISA's Known Exploited Vulnerabilities catalogue. Treat that as a lag, not as reassurance. The UK's National Cyber Security Centre has advised taking any system that cannot be patched immediately offline, and several research teams are known to be reproducing the work.
The real-world impact arrived before the exploits did. BambooHR took its service offline in the US, Canada and Ireland as a precaution and warned customers that payroll would be interrupted. In the Netherlands, MijnOverheid, DigiD, the lower house of parliament's website, the national cyber security centre and several education systems went offline while they patched. Those are the outages of organisations that knew they ran PHP and could act. The organisations that worry us are the ones that don't know.
AI found it, and AI weaponised it
Two weeks ago we wrote that the wrapper is the weapon: give a capable model tools and a goal, and it becomes a capable operator. PHP2Shell is the clearest demonstration yet, and this time it was the defenders' side of the table.
The researchers told reporters that frontier AI models "substantially reduced" the barrier to turning the flaws into exploits. Before that, demonstrating exploitability needed a very complex chain of steps. The models found the bugs, built the exploits, adapted them to different PHP versions and memory layouts, analysed failed attempts and iterated. The code in question had been in PHP for more than a decade, a PHP core developer had spotted signs of the out-of-memory flaw during a 2024 audit without finding a route to code execution, and the lineage traces back to research from 2004. It took an AI-assisted researcher a week.
That cuts both ways. The same capability that let one researcher find a 20-year-old bug in the most widely deployed web language is available to anyone with a proof-of-concept video and a model subscription. Edge providers saw payloads mutate to evade their rules within hours. Expect exploit variants per PHP version and per hosting setup, not one canonical exploit you can write a single signature for.
Why "just patch PHP" is harder than it sounds
For a modern application team with containers and a CI pipeline, this is a version bump and a redeploy. The problem is everything else.
PHP powers somewhere around seven in ten websites, and a large share of that is not sitting in a repository anyone maintains. It is in marketing sites a past agency built, in vendor appliances with a web UI, in internal wikis and ticketing tools, in the admin panel of a product the company stopped selling, in a subdomain nobody has looked at since 2021. Many of those run PHP 7.x or 8.1, where there is no package to install, only a source backport or an upgrade that may break the application on top. News coverage already expects embedded and unmaintained installations to stay vulnerable for a long time.
Then there are the parts of your exposure you do not run at all. BambooHR's outage interrupted payroll for its customers. If your HR, billing, support or hosting provider runs PHP in its web tier, their patch window is your risk, and you will not find out from your own scanner.
This is an inventory problem before it is a patching problem. The question for this week is not "have we patched PHP?" but "where is PHP reachable from the internet, which server API is it using, which version is it on, and who owns it?"
Mitigations that reduce exposure, and the ones that do not
PHP's advisory is unusually direct: "there are no complete mitigations, updating is the only safe choice." Until you can update, these are the measures the advisory says narrow specific attack paths. Apply them at the FPM pool or Apache configuration level, so applications cannot override them, and restart every worker afterwards.
- Against CVE-2026-109618: set
memory_limit=-1administratively, so the vulnerable allocation failure is less likely to happen. Set a lowpost_max_size, 8M for applications without file uploads and 32M where uploads are needed, withupload_max_filesizekept below it. Reducemax_input_nesting_leveland bound input variables, multipart parts and headers per part. - Against CVE-2026-109619: set
session.upload_progress.enabled=0, and consider leaving it off after patching if you do not use the feature. On PHP 8.5, setfatal_error_backtraces=0. Remove invalid or deprecated per-request settings that emit diagnostics before initialisation, and fix any attacker-reachable fatal errors and timeouts in upload, import and callback code. If performance allows,pm.max_requests=1on FPM makes the producer and consumer requests land on different workers. - At the edge: bound request size, multipart part count, headers per part and nesting depth at your reverse proxy or WAF, including for requests with no Content-Length. If an application does not use multipart requests, block them for it.
What does not help, in the advisory's words: hiding errors with error_reporting, display_errors, log_errors or the @ operator does nothing to prevent stale-state access. Container or cgroup memory limits are an availability boundary, not a security one, and a policy that kills every worker makes the outage worse. Do not use RLIMIT_AS or RLIMIT_DATA as a substitute, because they can cause exactly the allocation failure the exploit needs. And clean logs do not prove you are safe, because this all happens below the application layer.
How to spot attempts
PHP's advisory recommends turning on log_errors with a working error_log and error_reporting=E_ALL, then reviewing what comes out. Given how the exploits work, these are the patterns worth putting in front of whoever watches your web logs today:
- Unusual multipart requests followed by memory-limit fatal errors.
- Repeated HTTP 500 responses from the same client or the same path.
- Unexpectedly large or malformed PHPSESSID cookies in responses, which is the memory disclosure path leaking worker memory into a cookie.
- Unexplained PHP worker churn, with FPM or Apache children dying and respawning.
Treat any of these on an unpatched host as a potential compromise, not a performance glitch.
How Kervo AI handles this
PHP2Shell is the kind of event Kervo AI was built around: a single critical bug, scattered across an estate nobody has a complete map of, where the right order of work depends on exposure rather than on the CVSS score, which is 9.2 for everyone.
- Find every reachable PHP host, including the forgotten ones. External attack surface management continuously discovers your internet-facing assets, fingerprints the web stack behind each one, and flags the PHP versions and server APIs it sees. The agency microsite and the retired admin panel show up next to the production app.
- Rank by how exploitable the host actually is. Vulnerability management scores each affected host on severity, exploitability and business impact. An internet-facing mod_php server on PHP 8.1 with no vendor patch available sits at the top. An internal PHP-FPM tool behind SSO that only its own team can reach does not.
- See where a foothold would lead. PHP2Shell gives an attacker the web worker's privileges on one box. Attack paths show what that worker can reach: the credentials in its environment, the database it talks to, the cloud role attached to the instance. The host that is one hop from your crown jewels gets patched first.
- Watch your vendors' exposure, not just your own. Vendor risk monitors the external posture of the third parties you depend on, so you learn that a provider's web tier is still on a vulnerable PHP build from your own dashboard, rather than from their status page.
- Let the analyst do the legwork. The AI Analyst investigates each affected host, works out whether a package update, a source backport, a configuration mitigation or a vendor ticket is the right fix, drafts it, and pushes it once you approve.
What to do today
- Patch anything on a supported branch now. Update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or take the distribution package that contains the fix. This is an emergency change, not a next-patch-cycle one.
- Inventory everything that serves PHP over the internet. For each host, record the version, the server API, who owns it and what it can reach. Prioritise mod_php, then anything on PHP 8.1 or older.
- Apply the configuration mitigations on hosts you cannot patch today. Set them administratively and restart the workers. Then put a date on the upgrade, or follow the NCSC's advice and take the host offline.
- Tighten the edge. Enable your WAF or CDN provider's PHP2Shell rules and cap multipart request size and complexity at the proxy. Treat this as a stopgap, since payloads are already mutating.
- Look for the indicators on everything that was exposed between 20 and 21 October. Memory-limit errors after multipart requests, 500 bursts, strange PHPSESSID cookies and worker churn.
- Ask your vendors. Any provider that runs a PHP web tier and handles your data should be able to tell you their patch status today.
If you want to see which of your hosts are reachable, which version they are on and where a web worker on each of them could get to, book a demo and we will map it with you.
FAQ
Is PHP2Shell being exploited in the wild?
Exploitation attempts against both CVEs were reported by a global honeypot network from 14:19 UTC on 21 October 2026, and a major CDN reported early attacks and mutating payloads. As of 22 October there is no public confirmation of a successful compromise of a named organisation, and neither CVE is in CISA's Known Exploited Vulnerabilities catalogue. Given that a proof-of-concept video leaked and the research is being reproduced, assume exploitation is imminent for any exposed host.
Which PHP versions fix CVE-2026-109618 and CVE-2026-109619?
PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, plus PHP 8.6.0 RC4. PHP 8.1 and older get no release from the PHP project, but minimal source backports exist for 7.4, 8.0 and 8.1 on dedicated GitHub branches, and distributions and LTS vendors are shipping their own patches.
Does a WAF or CDN rule protect me?
It reduces exposure and buys time. Edge providers enabled rules before the patch and have said plainly that they are a stopgap, and that attackers were already changing payloads to evade them. The only complete fix is the PHP update.
Am I affected if my application does not use sessions or file uploads?
Yes. The vulnerabilities are in PHP's own request handling, and a working exploit has been shown to fire from a single unauthenticated request before application code runs. The session upload-progress path works without session_start(), and the out-of-memory path runs before application code on mod_php. Disabling upload progress and the PHP 8.5 fatal error backtrace closes specific paths, not all of them.
Is PHP-FPM safer than mod_php?
Somewhat, in the exploit paths published so far. PHP rates mod_php the highest risk because it runs request shutdown even when startup fails, and no complete PHP-FPM exploit for CVE-2026-109618 has been demonstrated. The stale-state bug, CVE-2026-109619, is validated against both mod_php and FPM, although the FPM path needs the attacker's requests to land on the same worker. Every server API that serves web requests is in scope, so patch all of them.
Sources
- PHP: security advisory for CVE-2026-109618 and CVE-2026-109619
- PHP Security Advisory GHSA-w8hw-w9fx-j79w: CVE-2026-109618, RCE via out-of-memory corruption
- PHP Security Advisory GHSA-6wmf-4rv5-p3rp: CVE-2026-109619, RCE via stale global state
- NIST National Vulnerability Database: CVE-2026-109618
- NIST National Vulnerability Database: CVE-2026-109619
- CISA: Known Exploited Vulnerabilities Catalog
- The Hacker News: PHP issues emergency patches for two critical PHP2Shell RCE flaws as exploit attempts emerge
- SecurityWeek: PHP2Shell, mass exploitation looms for leaked critical PHP flaws
- Help Net Security: PHP2Shell, critical PHP vulnerabilities patched, update now
Want to see this on your own environment?
Your real attack paths, coverage gaps and compliance posture, rather than a scripted demo.
