Skip to content
16 min read

php2shell red team attack surface and detection

Por Basilisk OffSec ·

php2shell pairs CVE-2026-109618 and CVE-2026-109619. A technical guide to attack surface, authorized pentest, and detection for red teams.

In this article

php2shell is the name given to the pair CVE-2026-109618 and CVE-2026-109619, two critical PHP runtime flaws disclosed on October 21, 2026 that, in the scenarios confirmed by official advisories, enable unauthenticated PHP RCE on installations that serve HTTP requests.

In addition, the official notice in the 2026 php.net archive places the risk in the engine that processes web requests, not in a CMS plugin. That is why this piece focuses on attack surface, inventory during authorized pentest work, and defensive hunting. By contrast, the sibling article on basilisk covers the operational patch checklist. That split keeps the red team from cannibalizing the remediation guide while still delivering a useful threat model.

What the anatomy of php2shell reveals across both flaws

CVE-2026-109618 describes corruption tied to an out-of-memory condition during initialization of internal request data, while CVE-2026-109619 describes global state that survives freed memory and is reused by the next request on the same worker. Together they form the PHP memory corruption nicknamed php2shell.

How OOM leaves a request in an invalid state

In advisory GHSA-w8hw-w9fx-j79w, the PHP security team explains the role of longjmp(). The engine used that mechanism to abort a request when memory ran out. At certain points, part of the request structure was already reachable. However, it was not yet fully initialized. If an allocation failed at that moment, the cleanup path could treat invalid data as valid. As a result, the engine kept reading or branching over that incomplete state.

How stale state crosses requests on the same worker

The second identifier, CVE-2026-109619, is tracked in GHSA-6wmf-4rv5-p3rp. It covers worker-global fields that point into request memory. That state must be reset before the heap is released. When a fatal error, a diagnostic path, or a session and upload path interrupts the flow at the wrong moment, the global pointer remains. After that, the next request in the same persistent process can consume the leftover value. In class terms, the first CVE combines weak handling of an exceptional condition with use of uninitialized state. The second is a classic use-after-free across requests.

Where sources diverge on scope and score

Researchers and cloud coverage, including Cloudflare, place exploitable paths as far back as PHP 5.4 in some configurations. The official notice and the GHSAs, however, list fixed lines as 8.2.35, 8.3.36, 8.4.27, and 8.5.12. There are also minimal source backports for 7.4, 8.0, and 8.1. Reach back to 5.4 is a researcher and third-party claim. It is not a closed inventory from the PHP CNA for every legacy release.

The score published by the PHP team and reflected by CERT-EU, NHS England, and Datadog is CVSS v4.0 9.2 for both. A 10.0 circulated in the pre-disclosure leak. In addition, NVD and vendors such as Red Hat may publish different v3.1 vectors. In inventory work, record the score source and do not mix v3.1 and v4.0 scales.

In practice, what I see most often on engagements is a team treating both php2shell CVEs as a single patch ticket. That choice erases the precondition difference. Teams that separate OOM during request cleanup from worker reuse place sensors more accurately and prioritize better when inventory shows mod_php versus FPM.

Which preconditions and attack surfaces actually matter

The surface confirmed by php.net covers every PHP installation that serves web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP, and LiteSpeed. Risk is described as highest for mod_php, with a demonstrated case in which an unauthenticated request triggers the issue before any application code runs.

How SAPI and persistent workers change the window

CISA, in its October 21, 2026 alert, stresses that every installation serving HTTP is in scope. It also asks for inventory where PHP is embedded in third-party products. Persistent workers change the game for CVE-2026-109619. The producer and consumer of stale state need the same process.

On SAPIs that kill the child after a failed startup, the CVE-2026-109618 path can narrow. The OOM advisory says exactly that about FPM. That SAPI exits the child when startup fails and thereby avoids consuming invalid state on that branch. Even so, source analysis in the same advisory still flags FPM as susceptible at other moments. Not every branch has a fully demonstrated exploit. The PHP Foundation also confirms RCE on application paths under FPM. Process-per-request shrinks the stale-state window across requests. Yet that alone does not cancel OOM during cleanup if shutdown still sees partial memory.

What partial mitigations block and what they leave open

Another practical precondition is exposure of early body parsing, multipart handling, and session or diagnostic paths that run early. Partial mitigations cited by php.net, such as an administrative memory_limit=-1 for the OOM path, block confirmed routes. The same is true for session.upload_progress.enabled=0 with a worker restart for stale state. They still leave variants open. Therefore they do not make an install safe against php2shell. Common CMS apps show up in researcher demos, but the flaw is in the runtime. Application authentication is not a control for the branch that fires before the script.

The mistake that costs the most here is assuming that “we do not use uploads” or “we only run FPM” equals out of scope for php2shell. In real inventory, priority follows SAPI, package version, and internet exposure, plus worker reuse. The CMS name on the storefront almost never decides the risk.

How PHP memory corruption becomes code execution at a conceptual level

In bug-class language, an attacker does not need to break WordPress logic. The attacker forces the engine to keep operating on structures that no longer represent a valid request. Under CVE-2026-109618, cleanup after OOM reads or follows incomplete pointers and metadata. With enough control over content that fills or pressures request memory, that read becomes useful corruption. Under CVE-2026-109619, a cross-request use-after-free lets a second request interpret bytes shaped by the first. It may also interpret bytes that leak from other requests on the same worker.

The conceptual bridge to RCE matches other memory flaws in interpreters. Corruption or reuse of internal objects becomes control-flow diversion or a function call under attacker influence. Privileges are those of the web worker account. Memory disclosure, described by Wiz, Datadog, and the stale-state advisory as a possible side effect, can yield addresses and secrets. That makes an RCE chain more stable. None of that requires a public layout in this text. The operational point is that app authentication and a shallow signature WAF do not close the class. The idea that there is no RCE in application code also does not close php2shell.

Many people believe only a classic heap overflow with a published offset matters. They are almost always wrong, because here the trigger is the error path and the request lifecycle. In threat review, treat php2shell as a runtime flaw with shell impact under the web server user, not as a plugin CVE.

How to describe the attack chain at a high level without a PoC

At a high level, the php2shell chain begins with one or more specially crafted HTTP requests against an endpoint that PHP parses. For CVE-2026-109618, the conceptual goal is to provoke a memory failure or abort while request structures are only half built. Cleanup then operates on that state. For CVE-2026-109619, the sequence typically involves a request that leaves residual global state. Another request on the same worker then consumes that state before a full reset. The sought result is code under the Apache, FPM, or equivalent SAPI user.

Public sources diverge on in-the-wild exploitation as of October 21, 2026. CISA stated it had not observed exploitation at alert publication. Cloudflare reported attack traffic and payload mutation against rules already active. The Canadian Centre for Cyber Security spoke of a PoC being available without identified active exploitation on that date. SecurityWeek and watchTowr described attempts on sensors, and in some reports success was still limited. For red team and SOC work, the safe stance is to treat the post-leak window as hostile. Inventory plus patch beats third-party telemetry debates about php2shell.

Anyone who has already swept runtime inventory at a client knows that anomalous requests, workers under pressure, and unexpected child processes show up before any elegant webshell. If the engagement is authorized, document the hypothesis and passive evidence. Do not trigger the flaw on a third party’s production host or on any system outside the RoE.

How to assess php2shell exposure in an authorized pentest

In a pentest with formal written authorization, the correct assessment of php2shell is inventory and patch-level validation. It is not triggering the vulnerability. Collect interpreter version and distribution package version. Also collect the SAPI in use, presence of mod_php, FPM pools, containers, and appliances that embed PHP. Compare against 8.5.12, 8.4.27, 8.3.36, and 8.2.35. When the line is 8.1 or older, compare against the LTS vendor advisory.

The UK NCSC, in its alert on the critical PHP issue, asked for priority identification of internet-facing systems. It also asked for continuous monitoring of vendors that package the runtime. Validate that any banner or exposed phpinfo matches the installed package, because proxies and stale images lie. In a contracted client environment, prefer package reads and controlled restarts after patch. Avoid destructive proof. If scope requires impact demonstration, use an isolated lab that mirrors SAPI and version. Never use a third party’s production target. Look for indirect exposure, such as panels and products that declare embedded PHP without an easy upgrade path.

  1. Inventory hosts, containers, and appliances with PHP answering HTTP, with package and SAPI evidence.
  2. Compare the running version with 8.2.35, 8.3.36, 8.4.27, or 8.5.12, or with a documented LTS backport, and mark exposure when the fixed floor is missing.
  3. Record network exposure, worker reuse, and RoE limits, without triggering OOM or use-after-free on a production target.

On authorized engagements, the criterion I use is simple. A version below the fixed floor plus a web SAPI equals a critical php2shell exposure finding, with package and configuration evidence. Trigger OOM or use-after-free on the target only if the RoE says so explicitly and the environment is disposable. Otherwise you mix validation with an incident.

Which log signals and public indicators to watch

Useful signals for php2shell appear in three layers. The first is the request. The second is PHP or web server logging. The third is the process. The Datadog Security Labs material on php2shell describes correlation among anomalous submissions, fatal memory-limit errors during request initialization, and workers that spawn a shell.

Observed signalWhat it may indicate
Fatal memory error with origin “Unknown on line 0”Failure during request initialization, before the script
Frequent Apache or FPM child restartsWorker under pressure or crash after an anomalous request
Spike in large bodies or multipart outside baselineMemory pressure or aggressive parsing
Shell child process under the web server UIDPossible post-exploitation after RCE in the worker
New webshell in a writable directoryClassic persistence after compromise

Fatal memory errors before the script belong to the same IOC family. The same is true for Apache child restarts with segmentation faults. Spikes in large bodies or multipart outside baseline also belong there. Unexpected child processes under the web server UID complete the picture. CISA and the Canadian alert ask defenders to watch PHP workers that launch shells, download tools, or create atypical processes, files, accounts, and outbound connections.

Classic post-exploitation still applies. New webshells in writable directories, network-tool downloads from the worker, cron or systemd services created by the PHP user, new local accounts, and atypical outbound connections all matter. No single signal proves php2shell. Legitimate memory spikes and bad deploys also produce OOM. Strength comes from temporal correlation among request anomaly, worker failure, and execution.

In hunting, the shortcut that misleads most is chasing only known webshell strings. On disclosure day, worker noise and shell children usually appear first. I would start with Apache and FPM process trees. Only afterward would I tighten on files tied to php2shell.

How to think about php2shell detection with Sigma and WAF at a high level

Sigma-style rules for php2shell detection should describe logic, not a payload. Generic conditions include a web server or FPM pool parent creating a shell interpreter or download utility. That matters especially after a burst of fatal memory errors or child restarts. Another family correlates POST methods with multipart fields or headers outside the application baseline and an error response in the initialization phase. Thresholds must come from the environment’s legitimate traffic, because real uploads and heavy imports exist.

On the WAF side, Cloudflare described managed protections for php2shell enabled on October 21, 2026 at 03:02 UTC. They covered Free and paid plans with WAF. The post discusses a set of anomalous-execution rules and full-transaction detection. That detection combines request and response signals in the same HTTP transaction. It thereby reduces false positives and can block a suspicious origin response. That is defense in depth. Cloudflare and php.net both repeat that only the patch closes the issue. Attackers were already trying to mutate traffic against the rules.

Detection without inventory becomes theater. The Sigma rule or WAF I would keep on tomorrow is the one that alerts on anomalous child processes and initialization failures tied to php2shell. Meanwhile the patch ticket for fixed versions needs an owner and a deadline. WAF alone is not a permanent risk acceptance.

What to do in incident response and php2shell remediation

Full remediation of php2shell means updating to PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35. An equivalent path is applying the LTS vendor package and restarting every worker. If the line is 8.1 or older, the PHP project does not ship a normal release. It published minimal source backports for 7.4, 8.0, and 8.1. Cross-guidance from CISA, NCSC, and the Canadian Centre is to isolate or remove from exposure systems that cannot reach a fixed line. Configuration mitigations in the official notice reduce specific paths. They do not replace the fixed binary.

In incident response, treat any evidence of a shell under the worker as compromise until proven otherwise. Isolate the host or pool. Preserve access logs, the PHP error_log, the service journal, and process telemetry. Hunt for webshells and persistence. Rotate credentials that could have lived in worker memory. Validate patch level across the whole fleet, not only on the symptomatic host. Side effects of the patch can include changed OOM behavior and session paths. Test in staging when the calendar allows. Do not use that as an excuse to leave internet-facing systems vulnerable to php2shell.

After the patch, what usually remains is a forgotten appliance and a pinned container image. I would close the incident only after a rebuilt php2shell inventory. I would also require confirmation that no old worker is still standing behind the load balancer.

Frequently asked questions about php2shell

This section closes the questions that show up most often in red team engagements and war rooms on October 21, 2026 about CVE-2026-109618 and the broader php2shell set. The answers below separate what the official notice confirms from what still depends on third-party telemetry. They also reinforce the ethical limit of testing. Use them as a verbal checklist with the client or the SOC, without turning the FAQ into a PoC.

Is CVE-2026-109618 the same thing as php2shell?

Not by itself. Php2shell is the nickname for the pair CVE-2026-109618 and CVE-2026-109619. The first covers corruption via OOM during request initialization and cleanup. The second covers stale global state across requests on the same worker. In inventory and in the patch ticket, treat both together. In hunting and threat modeling, keep the precondition difference, because sensors and partial mitigations are not identical for php2shell.

Does application authentication block exploitation?

On branches where the trigger occurs before application code, no. The php.net notice and lab reproductions emphasize unauthenticated requests that reach the engine. CMS login controls are not the right control for this class. That is why the finding should be classified as php2shell runtime exposure, not as a plugin flaw or an authenticated form issue.

Is it enough to trust only the WAF until the patch lands?

Not as a complete solution. A managed WAF, such as the one Cloudflare described, can reduce exposure and buy time. There is still bypass risk and false-negative risk when the edge parser does not see what PHP sees. Isolating exposed systems remains the alternative when the patch is delayed. Permanent risk acceptance with WAF alone is a fragile decision in the face of unauthenticated PHP RCE under php2shell.

Are PHP 7.x and 8.1 fixed by the project?

The project does not maintain normal releases for those lines. It published minimal source backports for 7.4, 8.0, and 8.1 and points to distribution and LTS vendor packages. Without a confirmed fixed package, guidance from several authorities is to migrate or isolate. In an authorized pentest, record the EOL line as critical php2shell exposure until there is evidence of an applied backport and restarted workers.

Is mass exploitation already confirmed by every authority?

There is no single consensus as of October 21, 2026. CISA reported no observed exploitation in its alert. Cloudflare, watchTowr, and other firms reported attempts or attack traffic. The Canadian Centre spoke of a PoC being available without identified active exploitation on that date. Treat the divergence transparently and prioritize patching plus process monitoring tied to php2shell.

How do you prove exposure without exploiting?

Compare version and package with the fixed releases, confirm SAPI and network exposure, and document the result. In your own lab or in an environment authorized by the RoE, any proof-of-concept stays isolated. Against a third-party target without formal authorization, any trigger is illegal and outside ethical scope. Acceptable report proof is usually package plus configuration plus php2shell surface mapping, not an induced crash in production.

Conclusion

CVE-2026-109618 and CVE-2026-109619 move the conversation from plugin bugs to a runtime flaw. The impact is a shell under the web server user. For red team work and for detection, the useful reading of php2shell is to inventory SAPI and patch level. It is also to correlate initialization errors with anomalous child processes. Configuration mitigations enter as path reducers, never as a full close of the risk.

Most environments gain more from a fleet fixed on 8.2.35, 8.3.36, 8.4.27, or 8.5.12, or on a verified LTS equivalent, than from debating which lab saw the first php2shell exploit. The answer changes when PHP is embedded in an appliance with no update channel. There the first step becomes isolation and pressure on the vendor. Compromise hunting should assume that the window after October 21, 2026 was already hostile.

This text is informational and educational about php2shell and the identifiers CVE-2026-109618 and CVE-2026-109619. It does not replace assessment by your vendor, your security team, or the owner of the environment. Technical tests should run only on infrastructure you own or with formal written authorization from the system owner.

Use your Canverly account to comment and interact.

Sign in to comment

Enter your email to sign in or create your account.

We will send you a 6-digit code, no password needed.

Related posts

No comments yet

Be the first to comment.

Leave a comment

Sign in with your Canverly account to comment. You can use the same account on any site in the network.