Latest research · AI security certification: which one fits which job in 2026

PHP vulnerability CVE-2026-109618 and CVE-2026-109619 (PHP2Shell)

PHP2Shell (CVE-2026-109618, CVE-2026-109619) is unauthenticated RCE in PHP itself. Patch to 8.5.12/8.4.27/8.3.36/8.2.35, and know why your scanner stays silent.

October 22, 2026MarkCyber ResearchcriticalCVE-2026-109618CVE-2026-109619
Share
Nested request packets pour into an indigo server engine under three website windows while a magnifying-glass scanner shows a check mark over the apps and an orange lightning bolt cracks the engine open to a terminal window, illustrating the PHP2Shell vulnerability CVE-2026-109618 and CVE-2026-109619 in the PHP runtime.

The PHP vulnerability pair known as PHP2Shell, CVE-2026-109618 and CVE-2026-109619, lets an unauthenticated attacker run code inside the PHP engine itself, before any application line executes. Both are rated CVSS v4.0 9.2 by the PHP security team, and the fix landed on October 21, 2026 in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. What makes this one different from the usual WordPress-plugin headline is where the flaw sits. It is in the runtime, so a hardened application on an unpatched PHP is still exposed, and the scanners most teams trust will stay quiet.

That quiet is where we expect most of the damage. We have already watched teams run a clean dependency scan this week and conclude they are safe. They are not, and the gap is structural, not a tuning problem. We will come back to it, because it changes how you verify this one.

What happened

The disclosure did not go to plan. Details leaked online on October 20, a day before the embargo, which pushed the PHP team to move the release forward to October 21 at 14:00 UTC. By then attack infrastructure was already moving.

  • August 11, 2026: Calif reports the first bug to PHP, and Wiz reports its findings days later, both crediting heavy use of frontier AI models to turn a decade-old flaw into a working exploit.
  • October 17, 2026: Amazon Threat Intelligence records an exploitation attempt against its MadPot honeypots, from an anonymization network, four days before anyone outside the embargo was supposed to know.
  • October 20, 2026: the CVE identifiers surface on Hacker News and social media; the PHP team posts an advance notice.
  • October 21, 2026, 03:02 UTC: Cloudflare pushes WAF rules to free and paid customers, saying it already saw attack traffic and payloads mutating to dodge the rules.
  • October 21, 2026, 14:00 UTC: the patched versions ship.

Amazon’s reading is the one to internalise: it says PHP2Shell is now being broadly exploited, and that you should start any investigation from October 17, not from the disclosure date. Confirmation is not unanimous. Huntress had not seen exploitation on its partner base as of late on October 21, and the PHP Foundation said it found no functional exploit in the proof-of-concept code that appeared after the leak. As of October 22 neither CVE is on the CISA KEV catalog. Treat the honeypot evidence as the floor and plan accordingly.

Which PHP versions are affected

The vendor advisories list four branches, but the honest scope is wider than the headline suggests. Calif traces the earliest exploitable path to PHP 5.4.0, and Fastly dates its oldest demonstrated path to 2012. One contributor on oss-security flagged that the advisory wording could be read as if only 8.2 through 8.5 are affected, which the source backports for 7.4, 8.0 and 8.1 contradict.

Branch Status Fix
8.5 before 8.5.12 Affected 8.5.12
8.4 before 8.4.27 Affected 8.4.27
8.3 before 8.3.36 Affected 8.3.36
8.2 before 8.2.35 Affected 8.2.35
7.4, 8.0, 8.1 Affected, end of life Source-only backports, no official release
5.4 to 7.3 Affected per researchers None from PHP; depends on your distribution

PHP says every way of serving requests is at risk: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. It rates mod_php highest, because there the demonstrated attack fires during request startup, before your code runs at all.

The exposure is enormous because the install base is old. Counting internet-facing services that disclose a version, Mallory found about three in four running PHP 8.1 or older, the branches that get no official release.

Most internet-facing PHP runs branches with no official fix
Most internet-facing PHP runs branches with no official fix
CategoryValue
PHP 4.x-5.157K
PHP 5.2-5.6797K
PHP 7.x858K
PHP 8.0-8.1213K
PHP 8.2-8.5693K

Source: Mallory, Shodan host counts, Oct 21 2026

Only the orange branch group can take the official patch. Everything to its left needs a distribution backport or a version upgrade, and the orange group is itself mostly unpatched: Mallory counted fewer than one in 250 supported-branch services showing a fixed build eight hours after release.

How the attack works

You do not need the exploit to defend against it, but you do need the shape, because that is what your detection and mitigations hang on. Both bugs come from one design decision: when PHP hits a fatal condition such as an out-of-memory error, it does not unwind cleanly. It jumps to a recovery point and abandons whatever it was doing, which can leave internal state half-built or pointing at memory about to be freed. Request cleanup then reads that state as if it were valid.

CVE-2026-109618 is the out-of-memory path. PHP’s advisory describes how an allocation failure during request startup can leave request memory in an invalid state that the shutdown routine then acts on. The trick is reaching that failure on demand while staying inside PHP’s apparent limits. Calif found several ways: a multipart request with no usable content length, parts carrying unlimited headers, and empty file controls with deeply nested field names that each expand into many internal allocations. Hundreds of those records can exhaust the default heap while the whole request body stays under the default upload size.

CVE-2026-109619 is the stale-state path, and it needs two requests on the same worker. The second advisory frames it as a producer and a consumer: one request leaves request-owned global state published after its memory is freed, and a later request on the same worker reads that state before normal initialisation resets it. The confirmed consumers are PHP’s own early paths, session upload progress and diagnostics raised while applying configuration, both of which run before a request is fully set up. Session upload progress is enabled by default and needs no call to session_start() in your code.

Wiz chained these primitives into unauthenticated remote code execution on stock WordPress, Drupal and Joomla. It separately showed an attacker reading PHP worker memory, which can hold passwords, tokens and keys from other requests, straight out of a response cookie. None of that depends on a flaw in the application. A plain “hello world” on a vulnerable build is reachable.

How to detect PHP2Shell activity

There is no clean application log line here, because the action happens below your application. The signal lives in PHP’s own error output and in what the worker does afterwards. Wiz points at unusual multipart requests followed by memory-limit errors or repeated HTTP 500s, oversized or malformed session cookies in responses, and unexplained worker churn. Fastly adds the detail that makes the error-log signal precise: an out-of-memory error reporting its location as Unknown on line 0 fired during PHP’s own request parsing, before any script ran, which is exactly the startup-time failure these bugs need.

The Sigma rule below reads an Apache error log and maps to ATT&CK T1190. It looks for that parse-time memory exhaustion rather than any single exploit payload, so it survives the payload mutation Cloudflare already observed.

Data source: Apache error_log from a host running PHP as mod_php (Sigma apache service)

title: PHP Request-Startup Memory Exhaustion (PHP2Shell Trigger)
id: e5b56032-7c97-4074-a0d7-dbb0f0b2b9d2
status: experimental
description: Detects the out-of-memory failure during PHP request parsing that opens the PHP2Shell chain (CVE-2026-109618), where the fatal is reported in Unknown on line 0 because it fired before any application script ran.
references:
    - https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
    - https://www.fastly.com/blog/fastlys-proactive-protection-critical-php-rce-cve-2026-109618
author: MarkCyber Research
date: 2026-10-22
tags:
    - attack.initial-access
    - attack.t1190
    - cve.2026-109618
logsource:
    service: apache
detection:
    oom_fatal:
        - 'Allowed memory size of'
    parse_time:
        - 'in Unknown on line 0'
    condition: oom_fatal and parse_time
falsepositives:
    - A badly tuned memory_limit under heavy legitimate uploads can exhaust memory during parsing; baseline normal upload traffic before alerting
level: high

One parse-time memory error is tunable noise. A burst of them, or a burst followed by segmentation faults in the worker, is the address-recovery phase of the attack and deserves a real look. The behaviour that never changes is what runs after success. A PHP worker should never launch a shell, so a mod_php or PHP-FPM process spawning a child like /bin/sh is the payload firing. The second rule reads Linux process telemetry and maps to T1059.004.

Data source: Linux process creation events (auditd, Sysmon for Linux or EDR), from a host running PHP

title: Shell Spawned By PHP Worker Process
id: c26a1d0a-54d4-4eec-aaba-8af384cd6d67
status: experimental
description: Detects a PHP worker (mod_php or php-fpm) spawning a shell interpreter, the post-exploitation step of PHP2Shell (CVE-2026-109618, CVE-2026-109619) when no application code calls a command function.
references:
    - https://www.wiz.io/blog/php2shell-php-rce
    - https://www.huntress.com/blog/php2shell-leaked-critical-php-vulnerabilities
author: MarkCyber Research
date: 2026-10-22
tags:
    - attack.execution
    - attack.t1059.004
logsource:
    product: linux
    category: process_creation
detection:
    selection:
        ParentImage|endswith:
            - '/php-fpm'
            - '/httpd'
            - '/apache2'
        Image|endswith:
            - '/sh'
            - '/bash'
            - '/dash'
    condition: selection
falsepositives:
    - Applications that legitimately call exec, system or shell_exec; baseline those endpoints and allowlist their command paths before enabling
level: high

Tune the parent image list to how your PHP actually runs, because a worker behind nginx looks different from mod_php under Apache. On any match, hunt back to October 17, 2026, when the first honeypot hit landed, not just to the disclosure date.

Mitigation

  1. Update PHP, then verify the running version. Move to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or your distribution’s patched package, and restart every worker so the new interpreter loads. On end-of-life branches, use a vendor backport or upgrade the branch. Updating is the only complete fix, and the WAF rules from Cloudflare, Fastly, AWS and others are a stopgap while you patch, not a substitute.
  2. If you cannot patch at once, break the specific paths. For CVE-2026-109619, set session.upload_progress.enabled=0 in php.ini, the FPM pool or server config, not through ini_set(), and on PHP 8.5 set fatal_error_backtraces=0, then restart every worker. For CVE-2026-109618, keep post_max_size low and enforce request-size limits at the frontend. The PHP advisory allows memory_limit=-1 as an interim measure, but note the trap it names: never substitute RLIMIT_AS or RLIMIT_DATA, because those make the allocation fail and trigger the very path you are trying to close.
  3. Do not trust a quiet scanner. This is the part that will catch teams out. Mallory found that Dependabot, composer audit and even container scanners stayed silent on vulnerable images, because the flaw is in the interpreter, not in the dependencies those tools read. Confirm the PHP version each web server actually serves, and note that a distribution can ship the fix without changing the version number, so compare your package release against the vendor advisory. That is the same version-trap that caught Plex owners whose build read as patched but was not. Making the runtime match the risk, rather than trusting a dashboard, is the kind of exposure our security engineering work exists to close.
  4. Account for appliances that bundle PHP. Firewalls, load balancers, NAS boxes and control panels carry their own PHP, and several management interfaces, including some from major network vendors, were not fixed in the first day. Restrict management access and follow each vendor’s advisory.

Bottom line

Find every place PHP serves a web request, including the appliances that hide it, and get each one to a patched build, then restart and confirm the running version. Do not let a clean dependency scan stand in for that check, because these flaws live in the runtime and scanners miss them. Put the two Sigma rules on your error and process logs, and hunt back to October 17.

Share