PHP2Shell is the name for two critical PHP flaws, CVE-2026-109618 and CVE-2026-109619, which the PHP project published on October 21, 2026. Both are rated Critical at CVSS v4 9.2 and need no login, so a crafted web request can be enough to run code on a PHP server. The fix is to update to PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12, or a later release on the same branch. If you cannot patch this week, inventory every PHP site, apply the documented workarounds, and check for web shells.
Working through this in production? See how we run a cybersecurity risk assessment.
What the two flaws do
PHP runs many of the sites and portals that small and mid-sized companies depend on, including WordPress sites, webmail and custom applications. Both flaws are memory-handling bugs in PHP itself, so the fix lives in the PHP runtime, not in the application code on top of it.
CVE-2026-109618 is titled “RCE via OOM corruption.” OOM means out of memory. When a request runs out of memory, PHP exits the request with longjmp(). The advisory says request memory can be reachable before it is fully initialized, so that early exit can leave it invalid, and request shutdown may then read or branch on it. The advisory names multipart form parsing as a route to trigger this, including a missing usable content length and unrestricted headers per part. Multipart is the format browsers use for file uploads.
CVE-2026-109619 is titled “RCE via stale global state.” Global state, including error, session, object and extension state, can outlive a request and still point to memory that has been freed. Code that runs before a request is fully initialized can then use that stale state, which is a use-after-free. Fatal errors that stop a request before it resets state are one producer. Session upload progress handling is one consumer. The advisory states that a strategically crafted heap layout can produce full remote code execution.
Both advisories carry the CVSS v4 vector AV:N/AC:H/AT:P/PR:N/UI:N. In plain terms, the attack comes over the network, needs no privileges and no user action, is rated high in attack complexity, and has attack requirements present.
Who is exposed
- Any PHP runtime on the 8.2, 8.3, 8.4 or 8.5 branches below the fixed release. Update to the fixed release for your branch.
- Older branches. The advisory ranges are written as “below” each fixed release, so older branches fall inside those ranges. No fixed release exists for them. Plan a migration, not a patch.
- Applications, not just PHP. A WordPress site, webmail system or custom portal is exposed through the PHP runtime underneath it. Updating the application or a plugin does not change the PHP version.
- Hosted sites. If a hosting provider runs PHP for you, the provider has to apply the update. Ask for the PHP version and the patch date in writing.
- Sites without PHP. A site served as static files with no PHP runtime is not exposed to these flaws. Confirm that with the host, because forms and site search often run PHP.
Exposure by how PHP runs
The advisories do not treat every PHP deployment the same. Use this table to understand where the evidence is strongest. It is for understanding, not for deciding which hosts can wait.
| How PHP runs | What the advisories say |
|---|---|
| Apache mod_php | Confirmed for CVE-2026-109618. Full remote code execution was validated over HTTP with default input and memory limits and normal prefork settings. Directory settings in .htaccess and php_value or php_admin_* are applied before request startup, which makes them an early path for CVE-2026-109619. |
| PHP-FPM | For CVE-2026-109618, source analysis suggests it is susceptible, but no complete exploit has been demonstrated. For CVE-2026-109619, the session lifecycle path was validated. It is conditionally exposed when a frontend such as nginx or mod_proxy_fcgi sends PHP_VALUE or PHP_ADMIN_VALUE parameters. Pool settings and .user.ini do not provide the same early path. |
| FrankenPHP | For CVE-2026-109618, source analysis suggests it is likely susceptible. For CVE-2026-109619, an early path was not established in the default configuration. |
| LSAPI | Conditional candidate for CVE-2026-109619. Application-specific exploits are likely but unvalidated. |
Treat any mod_php or PHP-FPM host as exposed until it is patched. The absence of a demonstrated path on another runtime is not evidence that the runtime is safe.
Exploitation: what is confirmed
Public sources do not agree on how far attacks have gotten, so keep the claims separate:
- PHP’s advisories do not state that either flaw has been exploited in the wild. They describe validated proof-of-concept results against mod_php and PHP-FPM.
- Cloudflare reports attack traffic against its customers, and says attackers changed their payloads to get past its protections.
- Secondary coverage disagrees about whether attacks had begun by October 21. The accounts have not been reconciled, so do not treat any single headline as settled.
Working assumption: the flaws can be reached over the network without credentials, PHP’s own testing demonstrated code execution, and every exposed PHP server is a target until it is patched.
Why configuration is not the fix
Workarounds reduce exposure and buy time. They do not close the flaws, and the advisories say so directly.
- CVE-2026-109618: the advisory calls
memory_limit=-1the primary configuration mitigation and states that it “is not a complete mitigation.” It also says updating is the only complete mitigation. - CVE-2026-109619: the advisory says there is no complete generic configuration mitigation. Disabling
fatal_error_backtracesdoes not cover other request-owned global or extension state. - Worker recycling: the advisory notes that multiple workers and recycling reduce success per request but do not remove the condition. Restarting workers is not a fix.
- Firewalls: a web application firewall reduces exposure. Cloudflare reports attackers changing payloads to get past its rules, so a rule set is not a patch.
Patching is the fix. Everything else in this article is for the window before you can patch.
This week: the checklist
| # | Action | Done when |
|---|---|---|
| 1 | List every server, site and staging copy that runs PHP, including vendor-hosted and forgotten sites | Each hostname has a recorded PHP version and runtime (mod_php, PHP-FPM, FrankenPHP or LSAPI) |
| 2 | Confirm the version on each host with php -v or the hosting control panel |
Each host reports 8.2.35, 8.3.36, 8.4.27, 8.5.12 or a later release on its branch |
| 3 | Update PHP through your OS package manager or host, then restart PHP and the web server, restarting every worker | The version is rechecked after the restart |
| 4 | Move any site on a PHP branch older than 8.2 to a supported release, because these fixes do not cover it | The move has an owner and a date |
| 5 | If patching must wait, apply the workarounds below after the application owner tests them | The change is logged and reviewed |
| 6 | Confirm a web application firewall is on for public sites | Status is recorded per site |
| 7 | Check for web shells and suspicious requests, reviewing logs as far back as they go and at least to October 20, 2026 | The review is documented, and anything unexplained is escalated |
For step 7, look for three things. These are general checks, not vendor-published indicators:
- PHP files added or changed recently in upload folders, cache folders or the web root.
- Multipart POST requests to PHP files from unfamiliar sources in the web server logs.
- Shell processes, such as
shorbash, started as children of PHP worker processes.
Workarounds for sites that cannot update yet
Each change alters how the application behaves, so have the application owner test it before it goes live. Bounding uploads can break large file uploads, for example.
- For CVE-2026-109618: set
memory_limit=-1, enforced administratively. Keeppost_max_sizeconservative and enforce the decoded request size at the frontend. Bound the number of input variables, multipart parts, headers per part, uploads andmax_input_nesting_level. If the application does not use multipart form data, block those requests at the frontend. Do not useRLIMIT_ASorRLIMIT_DATA. The advisory says they makemmap()fail at the memory limit, which reaches the vulnerable path. - For CVE-2026-109619: set
fatal_error_backtraces=0on PHP 8.5, administratively, and restart every worker. If you do not need session upload progress, setsession.upload_progress.enabled=0as well, administratively, and restart every worker.
If you find a web shell
A web shell is a file that lets an attacker run commands through a web page. Finding one usually means the server was compromised.
- Isolate first. Take the server off the internet, or take the site offline if the business can tolerate it.
- Preserve evidence. Copy the logs and the suspicious files before cleaning anything. Deleting the file first can erase what you need to learn how far the attacker got.
- Bring in incident response. DSE does not provide live digital forensics or incident response, so a firm that does should lead the response.
- Decide what the server could reach. Whether that triggers breach notification is a question for counsel, and the answer depends on the data the server could access.
Restore from known-good backups only after the entry point is closed.
Questions buyers ask
Do we need to patch if we do not run WordPress? Yes, if any site or application on your side runs PHP. The risk sits in the PHP runtime, so custom PHP applications, webmail and hosted portals count. Ask your developer or hosting provider which PHP version and runtime each one uses.
Is a firewall or CDN enough? No. A web application firewall reduces exposure, and Cloudflare reports attackers changing payloads to get past its rules. The patch is the fix. The firewall buys time while you apply it.
Our site is hosted by a vendor. Is it still our problem? Yes, as exposure, even though the vendor does the work. Get written confirmation of the patched PHP version for each hosted site, and keep it in your evidence file.
How do we know if we were already compromised? Check for unexpected PHP files and review web server logs back to at least October 20, 2026. An empty review is not proof of safety. If a file or log entry looks wrong, bring in incident response.
Does this trigger customer or regulator notification? Counsel decides that, based on what data the server could reach and whether it was accessed. Some notification deadlines run from discovery, so raise it early if you find a web shell.
Once the patches are in, external web application testing checks what an outside attacker can still reach on your public applications. For the difference between a scan and a test, read penetration test vs vulnerability scan. Restore plans matter here too: prove your backups restore before ransomware.
Key facts
- PHP's security advisories GHSA-w8hw-w9fx-j79w (CVE-2026-109618) and GHSA-6wmf-4rv5-p3rp (CVE-2026-109619), published October 21, 2026, rate both flaws Critical at CVSS v4 9.2 and list fixed releases 8.2.35, 8.3.36, 8.4.27 and 8.5.12 (PHP project, October 2026).
- PHP's advisory for CVE-2026-109618 states that updating to a patched PHP release is the only complete mitigation, and calls memory_limit=-1 the primary configuration mitigation that is not a complete one (PHP project, October 2026).
- PHP's advisories do not state that either flaw has been exploited in the wild, while Cloudflare reported attack traffic against its customers and attackers changing payloads to get past its rules (Cloudflare, October 2026).