A web server has a login page. It asks for a username and a password. Without the right credentials, we assume, nobody gets in. But can the server be taken over before our login code ever gets its turn to run?
On 21 October 2026 the PHP project announced two flaws that answer that question with a yes. Tracked as CVE-2026-109618 and CVE-2026-109619 and nicknamed PHP2Shell by the community, the flaws sit in the language runtime itself. The demonstrated mod_php path does not require an application bug: corruption can occur while PHP prepares the incoming request. Both flaws scored 9.2 on the CVSS v4.0 scale and require no authentication. PHP, security announcement, 21 October 2026
Two days later Siemens assessed its own software products one by one in SSA-566435. In this piece we first explain the logic of the bug in plain language, then look at what it means in an OT environment.
PHP is a programming language used to generate web pages on the server side; many management interfaces, portals and dashboards are written in it. A worker process is the program on a server that handles incoming requests one after another, taking the next request once the previous one is finished. Remote code execution (RCE) means an attacker makes the server run their own commands over the network. Use-after-free means a program keeps reading a block of memory it has already handed back as if it were still valid. CVSS is the common scale that rates vulnerability severity from 0 to 10.
What happens to a request on the server?
When a browser submits a form, PHP first reads the request: it parses the form fields, places them in the $_POST array, writes uploaded files to a temporary location; features such as upload progress can also access session state at this stage. Only after all of that does the application's own code run, that is, the login page we wrote. When the request is complete, PHP cleans up: it returns the memory it reserved for the request and discards temporary data. Datadog Security Labs, PHP2Shell analysis
This order matters. Preparation and cleanup are independent of the application. However carefully the login page is written, parsing the request comes first. Demonstrated attack paths reach these stages before application code runs; the impact depends on the PHP version and server interface. That is why the PHP project assigns the highest risk to installations running PHP as the mod_php module inside Apache: there, unauthenticated execution before application code was demonstrated. The cross-request path in the second flaw requires the same worker to handle multiple requests. PHP, security announcement
For the first flaw, PHP-FPM terminates the child when startup fails, so the demonstrated mod_php startup-cleanup chain cannot simply be transferred to FPM. PHP nevertheless includes all web-serving installations in its update guidance. PHP GHSA
The first flaw: a half-finished setup and a trusted counter
PHP puts an upper limit on the memory a request may use. When that limit is exceeded, it raises an out-of-memory error and aborts the request. The trouble lies in how the abort is done: PHP leaves the current work with a jump called longjmp(). The half-finished work is not tidied up; it is simply abandoned. Siemens ProductCERT, SSA-566435, description of CVE-2026-109618
Consider the table that holds the form fields. In the version Datadog examined, when PHP adds a new field it first increments the table's element counter and only then allocates memory for the field's name. If memory runs out at that exact moment, the counter says "one more element exists", but that element's name and value were never written. Although the request was aborted, the cleanup stage still runs and trusts the counter: while dismantling the table it interprets the phantom element as a real PHP value. Datadog Security Labs
An analogy: on an assembly line a counter says "five cards were fitted to this panel", but the power failed and the fifth card was never installed. During disassembly the hand reaching into the fifth slot takes whatever it finds there for a card and pulls it out. When cleanup treats uninitialized data as valid, attacker-influenced memory can be misinterpreted. Turning that into code execution also requires conditions such as valid memory addresses; ASLR and information leaks therefore matter.
According to PHP's advisory, the request that exhausts memory does not even need to be related to the structure that gets corrupted. Multipart form data can exhaust memory while appearing to stay within PHP's limits: requests without a usable content length, unlimited headers per part, and empty file controls combined with nested field names are the routes. GitHub Security Advisory GHSA-w8hw-w9fx-j79w
The second flaw: the trace left by the previous request
The second flaw grows out of the relationship between consecutive requests. A worker process serves many requests. Some of PHP's global variables (error state, session, object and extension state) live as long as the worker does; but some of them point to memory that belongs to a single request. The rule is that these variables must be reset before the request memory is released. GitHub Security Advisory GHSA-6wmf-4rv5-p3rp
A fatal error, such as memory exhaustion or exceeding the maximum execution time, can interrupt that reset. Or a warning produced during shutdown can repopulate state that had been reset. So when the worker takes the next request, it holds a pointer that is no longer valid. Normal initialisation would reset that pointer; but some operations run before normal initialisation and read the old pointer. That is a use-after-free. GHSA-6wmf-4rv5-p3rp
The PHP project confirmed two paths. The first exists only in PHP 8.5: the backtrace kept for a fatal error is not reset at shutdown, and a configuration warning in the next request reads it; command execution on mod_php was demonstrated this way. The second is file upload: the session upload progress feature is enabled by default even if the application never calls session_start(), and it prepares session state before normal initialisation; if memory runs out during the upload, that state is left behind. Stale-state reuse on this path was confirmed on both mod_php and PHP-FPM; that does not establish a complete, application-independent RCE chain on every PHP-FPM installation. GHSA-6wmf-4rv5-p3rp, Datadog Security Labs
This flaw has one condition: the request that leaves the trace and the request that reads it must land on the same worker. In a setup with many workers each attempt is less likely to succeed; but the flaw does not go away, the attacker simply sends more requests. Datadog Security Labs
Enlarge details
Why is changing settings not enough?
The first fix that comes to mind is removing the memory limit: memory_limit=-1. PHP suggests this as an interim measure but does not consider it complete. Even with the limit removed, the same jump can still run when the operating system cannot provide memory. Worse, imposing process-level memory limits (RLIMIT_AS, RLIMIT_DATA) can trigger exactly the allocation failure the flaw needs. For the second flaw, the settings session.upload_progress.enabled=0 and, on 8.5, fatal_error_backtraces=0 close only the confirmed paths; they do not cover other extension and error state. Hiding errors does not help either: with display_errors off, access to the stale state continues. PHP, security announcement, GHSA-w8hw-w9fx-j79w
The lasting fix is updating. The patch removes the abrupt jump on memory exhaustion and defers the error to a safe point; at a higher threshold it terminates the worker outright without running cleanup. Request-owned global state is also reset before reuse. GHSA-w8hw-w9fx-j79w
| Branch | Affected | Fixed release |
|---|---|---|
| PHP 8.5 | before 8.5.12 | 8.5.12 |
| PHP 8.4 | before 8.4.27 | 8.4.27 |
| PHP 8.3 | before 8.3.36 | 8.3.36 |
| PHP 8.2 | before 8.2.35 | 8.2.35 (branch support ends 31 December 2026) |
| PHP 7.4, 8.0, 8.1 | all | no official release; source patches only, or distribution and vendor packages |
| PHP 7.3 and earlier | all | no fix |
The table is based on information published by the PHP project and watchTowr. Source patches exist for the old branches, but no compiled release. That is a separate burden for manufacturers who have embedded PHP inside a device. PHP, security announcement, watchTowr, PHP2Shell FAQ
Organizations report different observations of exploitation in the wild. watchTowr says it saw exploitation attempts in its honeypot network from 21 October. Datadog relays that AWS reported attempts as early as 17 October, four days before public disclosure. Bitdefender wrote that it had seen no attempts as of 22 October. As of 23 October, CISA had not added either CVE to its Known Exploited Vulnerabilities catalogue. These reports cover different dates and telemetry. One organization seeing no attempts does not by itself disprove another’s observation. Exploitation attempts must also be distinguished from successful compromise. watchTowr, Datadog Security Labs, Bitdefender
23 October update: PHP reported an additional path involving an unusual session-serialization configuration: session.serialize_handler is configured as php_binary or php_serialize, then changed to php at runtime while upload progress remains enabled. PHP recommends session.upload_progress.enabled=0 for this case and plans to address it as CVE-2026-115560 in the next regular release. This additional guidance does not replace updating for the two flaws discussed above. PHP, 23 October advisory
What did Siemens do?
Siemens ProductCERT published SSA-566435 on 23 October. The document lists the impact status of various Siemens software products. The result is notable: none of the listed products is affected, and the reason is the same for all of them, "component not present". For Opcenter Execution Core, Polarion, Teamcenter Active Workspace, Tecnomatix Plant Simulation, the Xpedition family and others, Siemens states one by one that the product contains no PHP. Siemens ProductCERT, SSA-566435
Why does a list of unaffected products matter? Because a major manufacturer had to scan its product inventory for a flaw in a language runtime and say "there is no PHP in this software". That is exactly the work we need to do too. The listed products being unaffected does not establish that other vendors’ products or surrounding components contain no PHP. The real risk lies in the components around those systems that are hard to see in an inventory: device consoles, supplier portals, legacy dashboards, third-party add-ons. CISA also points out that PHP's presence may not be directly observable. The Dutch NCSC's tracking list held 635 products from roughly 430 suppliers as of 22 October. Engineering.com, PHP2Shell and manufacturers
Where does PHP hide in an OT environment?
The inventory review should extend beyond the corporate website. We can start with these questions:
| Where are we looking? | Question to ask |
|---|---|
| Web management interfaces of network devices | Routers, switches, cellular gateways: which language serves the interface, and which version? |
| Web dashboards of HMI and SCADA | Does the vendor's remote monitoring portal run its own web server? |
| Historian and reporting interfaces | Is there a dashboard in front of the database, and who installed it? |
| "Temporary" in-plant applications | The shift log, calibration tracker or maintenance form an engineer set up years ago? |
| Supplier and maintenance portals | What runs on the device the vendor supplied for remote access? |
This table is not the output of a scanning tool; it is an order we can follow while reviewing the inventory. For every PHP we find we need three facts: the version, how it runs (mod_php, PHP-FPM, php-cgi or another server) and who will update it. CISA puts every PHP installation that serves web requests in scope. CISA, alert of 21 October 2026
Embedded devices are harder. The PHP inside a device may be on an old branch, and no compiled release exists for that branch. Only the device manufacturer can update it, with new firmware. Until the manufacturer publishes an advisory, one compensating measure is network access control: narrowing who can reach the management interface. Siemens' general security recommendation points the same way: protect network access to devices with appropriate mechanisms and follow the operational guidelines for industrial security. Siemens ProductCERT, SSA-566435
What can we look for in the logs? Datadog suggests a few traces: the message "Allowed memory size of ... exhausted" appearing in the PHP error log together with Unknown on line 0, meaning the error occurred during preparation; memory errors from the same worker within a short period; crash records in the Apache log; and, as the most direct sign, a web worker spawning a shell process. In requests, field names the application does not normally use such as PHPSESSID or PHP_SESSION_UPLOAD_PROGRESS, multipart requests with hundreds of parts and excessively nested field names are conspicuous. Datadog adds that request size alone is a weak signal; parsing can allocate far more memory than the size on the wire. Datadog Security Labs
Why will this flaw be remembered?
What makes PHP2Shell important is not a bug in a single application. It is that a language runtime can fall into an untrustworthy state before it has even understood the request. Application-level login checks do not protect this preparation stage; a reverse proxy or access control in front of PHP can restrict requests before parsing. Moreover, PHP's own advisory says the same pattern may exist elsewhere: a memory error abandons an operation, and cleanup takes the half-finished state for valid. Datadog also expects more similar bugs to surface. Datadog Security Labs
On the OT side this reminds us of something: the web interface of a device in the field may be the least considered part of that device. We need to ask product by product, as Siemens did. The question we must ask is the same:
For every device and application on our site that has a web interface, do we know which software serves that interface and who will update it?
Sources
- PHP, security announcement and fixed releases, 21 October 2026
- GitHub Security Advisory GHSA-w8hw-w9fx-j79w, CVE-2026-109618
- GitHub Security Advisory GHSA-6wmf-4rv5-p3rp, CVE-2026-109619
- Siemens ProductCERT, SSA-566435, 23 October 2026
- CISA, Critical Vulnerabilities in PHP Require Immediate Patching, 21 October 2026
- Datadog Security Labs, PHP2Shell: detection, analysis, and remediation
- watchTowr, PHP2Shell FAQ
- Bitdefender, Technical Advisory: PHP2Shell Pre-Auth RCE
- Engineering.com, PHP2Shell: for manufacturers, the danger goes deeper than a website