---
title: "PHP2Shell: causes and remediation guide"
description: "Understand PHP2Shell lifecycle flaws, runtime upgrades, temporary mitigations, patch selection, and verification through the live Web request path."
language: "en"
url: "https://keendigit.com/en/insights/php2shell-remediation-guide"
author: "KeenDigit"
published: "2026-10-22"
---

# PHP2Shell: causes and remediation guide

Understand PHP2Shell lifecycle flaws, runtime upgrades, temporary mitigations, patch selection, and verification through the live Web request path.

**Sources checked as of October 22, 2026.** **Audience: PHP application operators, security responders, and engineers maintaining custom PHP builds.**

This article summarizes the cause, scope of impact, formal repair process, temporary mitigation measures and official patch implementation of the PHP2Shell vulnerability. The main text is cited using numbers such as [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1); all source links are listed in the appendix at the end of the text. The configuration fragment is a deployment template, which needs to be adjusted based on the actual version, business capacity, and configuration inheritance relationship.

## TL;DR: Repair steps and suggestions

1. **Upgrade the PHP runtime**: upgrade the relevant branch to at least **8.2.35, 8.3.36, 8.4.27 or 8.5.12**. For distribution packages, use the complete package version that the vendor confirms fixes both CVEs. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S10](https://keendigit.com/en/insights/php2shell-remediation-guide#source-10)
2. **Replace all old processes**: restart or roll over every PHP worker, hosting service, and container after upgrading, and confirm that old instances have exited.
3. **Verify through the actual Web request path**: check the Web SAPI, full package version, and running instance. Checking `php -v` alone does not establish that the live service is fixed.
4. **Run business regression checks and restore normal resource budgets**: test login, session handling, uploads, imports, and error handling. If the PHP memory limit was removed temporarily, restore an appropriate finite budget after patching.
5. **If an immediate upgrade is impossible**: restrict untrusted traffic before it reaches PHP. Evaluate disabling upload progress and PHP 8.5 fatal backtraces as described in Section 5. Configuration mitigations and WAF rules have limited coverage and cannot replace an upgrade. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

## 1. Vulnerability Overview and Risk Judgment

PHP2Shell in this article refers to two Critical level vulnerabilities officially disclosed by PHP on October 21, 2026. Both are related to the memory and request lifecycle management of the PHP engine, posing the risk of unauthenticated remote code execution. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

| Project                       | CVE-2026-109618                                                                                         | CVE-2026-109619                                                                        |
| ----------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| official name                 | RCE via OOM corruption                                                                                  | RCE via stale global state                                                             |
| core issues                   | Insufficient memory causes an abnormal jump, leaving a state that has not yet completed initialization. | The global state remaining in worker points to the released request memory.            |
| Typical occurrence time       | The initialization, execution or cleanup process of the current request                                 | The previous request leaves the status, and subsequent requests consume it in advance. |
| Is OOM a necessary condition? | Belongs to the core triggering mechanism of the vulnerability                                           | No; other fatal errors and cleanup post-diagnosis may also be involved                 |
| Fundamental repair direction  | Safely Handle Allocation Failures and Request Terminations                                              | Fix state ownership, cleanup timing and early initialization                           |
| Disposal requirements         | must be repaired                                                                                        | must be repaired at the same time                                                      |

Basis: Two official security bulletins and fix submissions. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)[S4](https://keendigit.com/en/insights/php2shell-remediation-guide#source-4)

### 1.1 Understanding affected deployments

PHP officially considers **all PHP deployments handling Web requests** at risk, including PHP-FPM, Apache mod\_php, php-cgi, FrankenPHP, and LiteSpeed. The demonstrated mod\_php attack can occur before application code runs, so login checks, framework middleware, and application upload validation cannot cover that path. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)

It is necessary to distinguish between "deployment needs to be fixed" and "a certain attack chain has been completely proven". Announcement of CVE-2026-109618: FPM will exit the child process after the request startup fails, blocking the corresponding cleanup path of mod\_php after the startup failure; however, the OOM path after successful startup is still at risk. The announcement also notes that the full FPM exploit for this CVE has not yet been demonstrated. This restriction cannot be used to deduce that FPM is safe, especially CVE-2026-109619 cannot be ignored. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

The immediate permission boundaries for successful exploitation depend on the identity of the process hosting PHP and the resources it has access to. Generally, attention should be paid to the website code, upload directory, database credentials, service tokens and internal network access capabilities; "remote code execution" does not mean naturally obtaining root permissions. The consequence judgment here is based on the process permission model, and the actual impact needs to be evaluated in conjunction with deployment permissions.

Ordinary one-time CLI scripts do not have the same HTTP entry; but processes that handle external tasks for a long time in CLI or embedded mode should still be included in the runtime and life cycle inventory. Only the CMS, framework or Composer dependencies are updated and the underlying PHP engine is not automatically replaced.

## 2. Cause analysis

### 2.1 First understand the two life cycles

PHP worker often handles multiple requests in succession. The memory allocated during the request can be released uniformly at the end of the request, while worker itself and some of its global fields continue to exist.

Therefore, the engine must maintain two constraints:

- **Initialization constraint**: Data visible to other codes must be in a state that can be safely read, traversed, and destroyed.
- **Lifecycle constraint**: once request memory has been freed, longer-lived fields must not continue treating addresses within that memory as valid state.

These two constraints correspond to the main failure modes of the two groups of vulnerabilities. The following process is a mechanism description that combines announcements and patch compilation. It does not mean that every deployment has exactly the same reachable path. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)[S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

### 2.2 CVE-2026-109618: OOM interrupted an unfinished status update

The old implementation uses a non-local jump of type `longjmp()` to handle OOM, and the associated path exits the current execution context through `zend_bailout()`. The danger is that a piece of C code may have published a new object, array, or request status to other code, but has not yet completed all field initialization; at this time, any allocation failure at the relevant time may cause the normal closing steps to be skipped. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

The failure process can be broken down into four steps:

1. Create or update the request internal structure and make it accessible.
2. Subsequent memory allocation fails and OOM is triggered.
3. The execution flow jumps away from the current function, and the code originally used to complete initialization or restore state is not executed.
4. Request cleanup continues processing these structures and treats invalid contents as valid fields or addresses.

The issue is not that running out of memory always causes RCE. Rather, **memory exhaustion changes control flow and violates the engine’s assumptions about valid structures**. The failed allocation need not directly involve the structure that is eventually read incorrectly. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

#### Why smaller requests can also run out of memory

The number of bytes in the request body and the heap usage after parsing are not the same thing. A field may correspond to multiple strings, array elements and metadata objects inside PHP; the input structural complexity will affect the degree of memory amplification.

Issues with multipart listed in the official announcement include: initial size check gap when available declaration length is missing, the number of headers for a single part is not sufficiently limited, and empty file controls still produce metadata, with nested names further increasing array workload. The application's own unwinding, decoding, or reassignment of input may also be a source of OOM. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

Two protective conclusions can be drawn from this:

- Request body restrictions must be implemented as much as possible before entering PHP, and the actual read length and structural complexity must be considered.
- Individually limiting the file size, number of files, or closing only one upload portal cannot cover all OOM sources.

#### Why application authentication may be too late

In mod\_php, the request body may be automatically parsed during the request initialization phase; even if the startup fails, related request cleanup will still be performed. Confirmed attack paths can therefore occur before application code. To reduce exposure at this stage, restrictions need to be placed at the reverse proxy, Web server, or other boundary that precedes PHP request processing. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

### 2.3 CVE-2026-109619: The request memory has been released, the global reference is still alive

This issue involves error, session, object, or extension status: the field is stored in a worker long-term access location, but the data referenced by the field belongs to a single request. As long as the reference is not properly cleaned up before the request heap is released, subsequent requests may encounter a dangling state, forming use-after-free. [S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

The official analysis divides the exploitation conditions into "producers" and "consumers":

| role or condition | meaning                                                                                               | Implications for protection                                                    |
| ----------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| state producer    | Put the state owned by this request into a location that can still be accessed later                  | To check whether the corresponding cleanup is completed after abnormal exit    |
| Status remains    | It was not cleared, or it was cleared and then refilled by a late operation.                          | Just clearing once at the earlier shutdown stage may not be enough             |
| worker reuse      | The same worker continues to process subsequent requests                                              | Multiple worker is just a scheduling difference, not a memory safety guarantee |
| advance consumer  | Read, release or determine the residual value before the corresponding state is initialized normally. | Must check INI, session and other paths before initialization                  |

These conditions need to be met in combination; any error log by itself does not prove that the vulnerability has been successfully exploited. [S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

#### It does not require OOM as a necessary prerequisite

Fatal errors can interrupt paired state publication and restoration. Compilation or parsing failures, uncaught errors, `require` failures, and execution timeouts can leave particular states behind. Non-fatal diagnostics late in cleanup can also repopulate error information that was already cleared. [S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

Therefore, changing `memory_limit` to unlimited does not cover this set of vulnerabilities.

#### "Before initialization" needs to be treated separately

The timing of the two types of confirmed consumers is different:

- **Early INI diagnostics**: Some configurations applied on request issue warning, notice or deprecation before normal executor initialization, and diagnostic processing may access the old error state.
- **session upload progress**: session may be processed in advance during the request body parsing process, but the regular module `RINIT` has not yet been completed; it cannot be inferred that the path does not exist because the application does not explicitly call `session_start()`. [S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

Not all INI configurations have the same risk timing. The directory-level configuration of mod\_php and the `PHP_VALUE` / `PHP_ADMIN_VALUE` passed in by the FPM front-end need to be distinguished from the ordinary `php.ini`, FPM pool startup configuration and FPM `.user.ini`. The latter ones have different configuration timing and cannot be collectively called the same early consumers. [S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

Turning off `display_errors`, `log_errors`, reducing `error_reporting`, or using `@` only affects the visibility of the diagnosis; the relevant internal state may have been accessed before deciding whether to output the log. [S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

## 3. Repair version and patch selection

### 3.1 Official upstream fix baseline

| Current PHP branch       | The first version to include this official fix | Suggestions                                                                                       |
| ------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| 8.2                      | 8.2.35                                         | Upgrade to this version or a subsequent version containing the same fixes                         |
| 8.3                      | 8.3.36                                         | Same as above                                                                                     |
| 8.4                      | 8.4.27                                         | Same as above                                                                                     |
| 8.5                      | 8.5.12                                         | Same as above                                                                                     |
| 8.1 and earlier versions | Upstream general support has ended             | Prioritize migration to supported branches; short-term check release or LTS manufacturer backport |

The version and support status are based on the official announcement of PHP, and the time baseline is October 22, 2026. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)

These are **branch-specific fix thresholds**. They cannot be replaced by a statement that every version below 8.5.12 is vulnerable: versions such as 8.2.35 and 8.4.27 in other branches already contain the fixes.

### 3.2 Check the full distribution package version

Distros often add security fixes based on older upstream versions. Acceptance should also check the release version, repository source, full package version and security bulletin.

For example, the Ubuntu 24.04 LTS fix package version listed for Ubuntu USN-8948-1 is:

```text
8.3.6-0ubuntu0.24.04.13
```

Its upstream part is still `8.3.6`, but the full package version of that distribution is included in this fix announcement. This conclusion only applies to the corresponding distribution and package source, and cannot be generalized to any build that also displays `8.3.6`. [S10](https://keendigit.com/en/insights/php2shell-remediation-guide#source-10)

### 3.3 Choosing the right patch

| scene                                              | Priority plan                                                                           | Key points for acceptance                                                              |
| -------------------------------------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| Using the distribution PHP package                 | Install security updates released by the manufacturer                                   | The announcement covers both CVE; the complete package version is correct              |
| Use the official PHP container or self-built image | Update the base runtime, rebuild and deploy                                             | The running instance uses the new image; all old copies are exited                     |
| Self-compiled supported branches                   | Use the official security version of this branch or the full official patch set         | Branch matching, dependency completion, extension compatibility and regression passing |
| Subject to 7.4, 8.0, 8.1                           | Prioritize vendor backport; evaluate official emergency source code branch if necessary | Identify behavioral changes and schedule migration to supported versions               |

Official patches have been released, and actual fixes should start from these patches. The code snippets in Section 6 are intended to illustrate design and review highlights and do not constitute a complete patch that can be applied independently. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S4](https://keendigit.com/en/insights/php2shell-remediation-guide#source-4)[S6](https://keendigit.com/en/insights/php2shell-remediation-guide#source-6)

## 4. Formal repair process

### 4.1 Inventory of the runtime that actually handles requests

It is recommended to form a brief ledger to record at least:

- Entry domain name or service, reverse proxy backend, PHP SAPI.
- PHP branch, full package version or image digest, build source.
- FPM pool, actual service unit, container or Pod, number of replicas.
- Extensions, main configuration and additional configuration files have been loaded.
- Are there other PHP versions, old deployment copies, or origin portals that can be accessed directly?

These are implementation suggestions so that "upgraded" can correspond to each actual traffic entry. Especially check if the command lines PHP and Web PHP use different versions, the image is built but the old container is still running, part of pool or the copy is not replaced, etc.

### 4.2 Select and deploy the correct update

Confirm the fix version as per Section 3, preferably using an existing trusted package source or controlled build chain. The update scope should include the component that actually hosts the request, such as the FPM package, the Apache PHP module, the CGI binary, or the service build in which PHP is embedded.

Before upgrading, keep the configuration and package list, and verify startup and key services in an environment similar to production. For self-maintained extensions, check build and run compatibility corresponding to version PHP. Just picking a seemingly relevant commit from another branch does not guarantee that the entire set of fixes has been implemented.

### 4.3 Restart or roll over running instances

Installing a file and loading new code into a process are two different things. The corresponding service should be restarted, or the rolling replacement should be completed, and the old worker and old container should be confirmed to have exited.

For mod\_php, restart the Apache process hosting the module. Services that embed PHP need their hosting process replaced. For FPM, clearing OPcache does not replace updating the runtime and retiring old workers.

When using graceful switching, you need to check whether the old generation process is still handling long connections or outstanding requests. The acceptance record should include the actual service, deployment version, change completion time, and exit results of the old instance.

### 4.4 Verify through real Web requests

It is recommended to combine the following pieces of evidence rather than relying solely on a single version command:

| evidence                                               | What can be proved                        | Can't prove anything alone                  |
| ------------------------------------------------------ | ----------------------------------------- | ------------------------------------------- |
| Package manager or image metadata                      | Installation sources and full builds      | Traffic has been switched to this instance  |
| Process and deployment status                          | worker or container completes replacement | The external entrance must be routed to it  |
| Restricted diagnostic results accessed via real portal | Actual Web SAPI and running configuration | Whether the release backport covers two CVE |
| Vendor announcement or complete patch record           | This bug fix is included in this build    | All replicas are deployed                   |

`PHP_VERSION`, `PHP_SAPI`, loaded configuration files, and emergency configurations can be checked through existing internal diagnostic capabilities, or temporary and access-controlled diagnostic portals. Make sure the request is not returned directly by CDN or the page cache; remove the temporary diagnostic entry when completed.

`php -v` usually only indicates the CLI binary currently selected by shell; commands such as `php-fpm -i` are not equivalent to verifying the existing worker that is receiving traffic. Do not expose the complete `phpinfo()` page to the public network for a long time.

### 4.5 Business regression checks and removal of emergency settings

Verify normal login, session reading and writing, form and upload, import, error handling and worker stability around the functions affected by this change. Check whether the error rate, response delay, memory peak, process exit and rebuild frequency are abnormal.

If `memory_limit=-1` is temporarily set, the limited budget matching the business capacity will be restored after the official patch takes effect; if `pm.max_requests=1` is set, the capacity-evaluated life cycle configuration will be restored after the repair is confirmed. Input size limits and source access controls can be retained as business needs dictate.

If compatibility issues arise during the upgrade, priority should be given to suspending the affected portal, restricting its external access, or adjusting the application before rolling back. Directly allowing the unrepaired runtime to serve the public network again will reopen the original risk.

## 5. Mitigation measures when immediate upgrade is not possible

This section is intended for short-term reduction of exposure or improvement of availability. Each measure only covers a specific path, and a combination of multiple measures is not equivalent to a complete repair. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

### 5.1 Prioritize traffic controls before PHP

If the service permits it, temporarily restrict sensitive endpoints to trusted sources or enforce access control before PHP. For upload workloads, limit request-body size, field counts, part counts, headers per part, and nesting depth. Services that do not need multipart can reject it at the frontend. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

These restrictions are to cover all entrances to PHP. Only intercepting the URL named "upload" will miss other entries that are still automatically parsed by PHP in the request body. For cases such as chunked transfers, lack of available declared length, etc., the limit should be based on the actual read size; the application should also have its own output size budget when decompressing or expanding the content again.

### 5.2 FPM pool configuration template

Place the following settings in the **FPM pool configuration section that actually serves requests**, not verbatim in `php.ini`. The 8M and 4M values are examples to adjust for the workload. Leave room for form fields and multipart boundaries when limiting the entire POST request. [S11](https://keendigit.com/en/insights/php2shell-remediation-guide#source-11)[S12](https://keendigit.com/en/insights/php2shell-remediation-guide#source-12)

```ini
; Temporary mitigation: evaluate capacity before applying.
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 4M
php_admin_flag[session.upload_progress.enabled] = off
```

**PHP 8.5** only, plus:

```ini
php_admin_flag[fatal_error_backtraces] = off
```

The functions and boundaries of each are as follows:

| Configuration                         | expected effect                                                         | Description of restrictions that must be retained                                                                                                     |
| ------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `memory_limit=-1`                     | Remove the predictable PHP request memory upper limit trigger condition | It does not prevent underlying allocation failure; canceling the original budget may increase the risk of memory exhaustion and service interruption. |
| Smaller `post_max_size`               | Reduce the size of data entering the parsing process                    | Unfixed parser has known gap; memory amplification cannot be prevented independently                                                                  |
| `upload_max_filesize < post_max_size` | Limit single file size and reserve request overhead space               | Does not constrain all fields, metadata, or in-app allocations                                                                                        |
| Close upload progress                 | Block the confirmed session related path                                | Does not cover other global state variants                                                                                                            |
| PHP 8.5 close fatal backtrace         | Block confirmed related status producers                                | Does not cover other paths such as session                                                                                                            |

The measure boundaries come from the official announcement; for pool syntax and management-level configuration semantics, see the PHP manual. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)[S11](https://keendigit.com/en/insights/php2shell-remediation-guide#source-11)

Management-level `php_admin_*` settings cannot be overridden by applications via `ini_set()`. All pool, directory-level and front-end incoming configurations should still be reviewed to confirm that the values ​​on actual requests are as expected. After modification, rebuild all worker to prevent existing processes from continuing to hold the old state.

If you choose to modify `php.ini` directly, the syntax should be changed to:

```ini
memory_limit = -1
post_max_size = 8M
upload_max_filesize = 4M
session.upload_progress.enabled = Off
```

Unlike `php_admin_value` in pool, merely setting `memory_limit=-1` in `php.ini` does not prevent the app from modifying it again. The framework, application code, and other configurations should be checked to see if they have reset the limited value; when enforcement is required, use the management-level settings appropriate for the current SAPI and check the actual effective value. [S11](https://keendigit.com/en/insights/php2shell-remediation-guide#source-11)[S12](https://keendigit.com/en/insights/php2shell-remediation-guide#source-12)

Add `fatal_error_backtraces = Off` only for PHP 8.5. Do not use application-level `ini_set()` as a workaround for disabling upload progress, and do not rely on FPM `.user.ini` to make it effective before request parsing. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)

### 5.3 Manage the cost of removing PHP memory limits

`memory_limit=-1` is a temporary path mitigation for unfixed environments and should not be copied as the long-term default configuration. When an application or request gets out of control, it can use up more of the host's memory. Therefore, before use, you should evaluate the number of concurrencies, peak single worker, and total service capacity, and deploy front-end input limits. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

Container or cgroup memory limits can provide availability boundaries but do not guarantee that allocations will never fail; the entire container, master, and all worker may also be terminated when the limit is triggered. Isolation granularity and termination strategies need to be evaluated in conjunction with deployment and cannot be called complete protection for these two CVE. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

Do not replace the above strategies with `RLIMIT_AS`, `RLIMIT_DATA`, or corresponding process address space restrictions; they may directly cause the underlying allocation to fail into the still problematic OOM path. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)

### 5.4 Nginx Configuration Example

Applicable to deployment where Nginx forwards requests to PHP-FPM. It can be set at the configuration level of the actual hosting service:

```nginx
client_max_body_size 8m;
fastcgi_request_buffering on;
```

`client_max_body_size` limits the request body size; `fastcgi_request_buffering on` lets Nginx read the complete request body first and then send it to the FastCGI backend. Whether it takes effect in a certain `server` or `location` needs to be checked in conjunction with the existing inheritance and coverage relationships. [S13](https://keendigit.com/en/insights/php2shell-remediation-guide#source-13)[S14](https://keendigit.com/en/insights/php2shell-remediation-guide#source-14)

**Only when the business does not need multipart**, you can add a rejection rule to the corresponding service entrance:

```nginx
if ($http_content_type ~* "multipart/form-data") {
    return 403;
}
```

This is a simple entry restriction template using `if` and `return`, not a general filtering rule for parser vulnerabilities. Verify the configuration syntax and normal requests before deployment, and check whether the custom `error_page` redirects 403 requests to PHP. String matching does not provide complete guarantees on all parsing differences. [S15](https://keendigit.com/en/insights/php2shell-remediation-guide#source-15)

In addition, these configurations do not automatically limit the amount of data, the number of fields, or the number of PHP objects that can be decompressed by the application; businesses that need to upload should use additional restrictions that understand the structure of their requests.

### 5.5 Optional mitigation: one request per FPM worker

For FPM deployments that can afford the overhead, short-term setups can be evaluated:

```ini
pm.max_requests = 1
```

And rebuild the existing worker. It blocks the described cross-request chain at the worker reuse level, but will increase process creation and initialization overhead; at the same time, it cannot repair the same request OOM and cleanup issues of CVE-2026-109618. When the value is smaller but greater than 1, there is still a request reuse window. [S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)[S11](https://keendigit.com/en/insights/php2shell-remediation-guide#source-11)

### 5.6 WAF and Cloudflare coverage limits

Cloudflare has announced deployment arrangements for protection against PHP2Shell, including the Free plan. When using its services, you should check whether the actual traffic passes through the proxy, whether the protection rules are in effect, and whether the origin site can be directly bypassed; for paid plans, you also need to check the configuration and exceptions of the corresponding Managed Rules. [S16](https://keendigit.com/en/insights/php2shell-remediation-guide#source-16)

Some of the detections described by the vendor utilize response signals, so all protections cannot be interpreted as "every attack is blocked before reaching PHP". WAF can help reduce exposure and provide observational information, but continued upgrades to PHP are still necessary. [S16](https://keendigit.com/en/insights/php2shell-remediation-guide#source-16)

### 5.7 Why common measures are insufficient

| measures or judgments                                | shortcomings                                                                                                                                   |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Only close `file_uploads`                            | Cannot cover all multipart processing and apply its own OOM path                                                                               |
| Setting `enable_post_data_reading=Off`               | Change the behavior of automatically filling POST/FILES; the request body can still be read by the application and may disrupt normal business |
| Turn off error display, log or use `@`               | Internal diagnostic processing may still access the dangling state                                                                             |
| Increase the quantity of worker                      | Do not establish a safe state cleanup mechanism, nor eliminate the reuse of single worker                                                      |
| Configure only `disable_functions` or `open_basedir` | These limitations do not fix the C engine layer memory corruption                                                                              |
| Only check a version or a single copy once           | It cannot be proven that all entrances and running instances have been replaced                                                                |
| No exception logs are seen                           | It cannot prove that the vulnerability does not exist or that it has not been exploited before.                                                |

Among them, the configuration and vulnerability mechanism basis of PHP can be found in [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S3](https://keendigit.com/en/insights/php2shell-remediation-guide#source-3)[S12](https://keendigit.com/en/insights/php2shell-remediation-guide#source-12); the judgments about coverage, acceptance and permission boundaries are based on the implementation suggestions put forward by these mechanisms.

## 6. Implementation ideas and review points of the official patch

### 6.1 Use complete fixes for the correct branch

The representative official submission for PHP 8.5 is:

```text
31c0ea7d7ff1d1fccb6492e52dab544011628065
Avoid state corruption via bailout
```

The commit explicitly associates two CVEs, both to adjust the OOM exit mechanism and to fix global state that may be accessed during the initialization phase. Submit page with full diff see [S4](https://keendigit.com/en/insights/php2shell-remediation-guide#source-4)[S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5). Other branches should use their own official security releases or matching patches, and it cannot be assumed that changes to 8.5 can be directly applied to any older version.

### 6.2 OOM Repair: restore the processable state first, and then terminate the request

The formal implementation introduces two levels of soft and hard OOM processing: when the soft limit is reached, the pending status is recorded, and a controlled exit is performed at a safe location such as VM; the failable allocation interface allows the caller to explicitly handle the failure. For allocations that cannot directly return failure, if a higher hard threshold is expected to be exceeded, the process will be terminated directly to avoid continuing to process requests in an unsafe intermediate state. [S2](https://keendigit.com/en/insights/php2shell-remediation-guide#source-2)[S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

The following is an excerpt of the key code in 8.5 diff used to mark pending OOM:

```c
EG(delayed_oom).state = ZEND_OOM_STATE_PENDING;
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
```

VM interrupt handling and other safe locations subsequently call `zend_handle_delayed_oom()`. Its user code execution context uses a controlled unwind path; the hard OOM path calls `_exit(137)`. [S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

From a design perspective, the important changes are: **avoids arbitrarily crossing the C call stack when the structure is in an intermediate state, and places the exit at a location** that can maintain state constraints. After the soft limit is triggered, additional memory may be required to complete the process, so the new soft threshold cannot be understood as an absolute upper limit for the total memory of the process.

Nor can it be summarized as "PHP has deleted all `zend_bailout()`". The patch still uses relevant mechanisms in specific contexts; what is fixed is the dangerous exit timing and the accompanying state management. [S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

### 6.3 Update allocation callers and multipart parsing together

If you only change an allocation function to "return NULL on failure" and the original caller still assumes that a valid pointer is always returned, you will introduce new null pointer accesses or incomplete cleanup. The failable allocation interface in the patch needs to be reviewed together with caller checking and exception propagation. [S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

multipart related fixes also include performing cumulative checks based on actual read volume, reducing the processing of useless or duplicate headers, and adopting consistent exit and cleanup logic when OOM is pending. These changes both reduce resource amplification and make the parser comply with the new OOM protocol. [S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

For teams that maintain their own branches, it is recommended that the following issues be the focus of code review:

- Is the state visible to the outside world before it is fully initialized?
- After allocation failure or callback exception, is ownership still unique and unambiguous?
- Can you reach the unified cleanup exit if you fail midway?
- Can the cleanup function recognize uninitialized or freed fields?
- Is the parsing budget based on actual processing volume, not just trust request claims?
- Has the new failure return value been handled by all callers?

These are review questions summarized based on the fix mechanism, and are not the conclusion of an audit that has been completed for an unprovided code base.

### 6.4 Cross-request fix: initialization earlier, final cleanup later

Corresponding to CVE-2026-109619, the patch adjusts multiple life cycle boundaries at the same time. The files and operations listed below take PHP 8.5 official diff as an example. [S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

| location                                 | change direction                                                          | Problem solved                                                                                   |
| ---------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `Zend/zend_execute_API.c` etc.           | Reset executor status such as errors, exceptions, handlers, objects, etc. | After the request ends, there are still old references that can be accessed by the next request. |
| Startup path of `main/main.c`            | Call `php_basic_early_rinit()` before SAPI is activated                   | When an early consumer occurs, the relevant underlying state has not yet been initialized.       |
| Close path of `main/main.c`              | Destroy HTTP globals and mark it as undefined                             | The released value is still considered a valid object                                            |
| before the request heap is finally freed | Clean up the last error message again                                     | Late cleanup diagnostics repopulate error status                                                 |
| `ext/session/session.c`                  | upload progress The early path is initialized first session globals       | Regular module RINIT previously accessed old state                                               |
| Serialization related code               | Limit class parsing and user callbacks in early processing                | Execute additional user code when initialization is not complete                                 |

For example, the startup sequence includes:

```c
zend_activate();
php_basic_early_rinit();
sapi_activate();
```

After HTTP globals is destroyed, add the status failure mark:

```c
zval_ptr_dtor(&PG(http_globals)[i]);
ZVAL_UNDEF(&PG(http_globals)[i]);
```

These excerpts illustrate two principles: **initialize before the earliest possible consumer, and perform final cleanup after the last operation that might recreate the state.** Resetting a pointer only during normal RINIT or an earlier shutdown stage may miss earlier or later accesses. [S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

### 6.5 Why is it not recommended to make your own "one-line repair"?

Replacing all `zend_bailout()` with `_exit()`, or just adding a null pointer check at a certain entry, would span a large number of different execution contexts. They may omit other status fields, or they may change destruction, extended callbacks, process hosting, and request end semantics.

For supported versions, full fixes that have already been released take precedence. The migration of own branches should record the source of patches, applicable baselines, conflict handling and behavior changes, and use corresponding upstream regression use cases and verification of this business process. The suggestions here come from an analysis of the patch's scope across allocator, VM, session and request lifecycle changes. [S4](https://keendigit.com/en/insights/php2shell-remediation-guide#source-4)[S5](https://keendigit.com/en/insights/php2shell-remediation-guide#source-5)

## 7. Emergency backport of PHP 7.4, 8.0, 8.1

PHP officially provides the minimum source code backport of three old branches based on the severity. The branch names are:

```text
PHP-7.4-CVE-2026-109618-109619
PHP-8.0-CVE-2026-109618-109619
PHP-8.1-CVE-2026-109618-109619
```

For branch links, see [S7](https://keendigit.com/en/insights/php2shell-remediation-guide#source-7)[S8](https://keendigit.com/en/insights/php2shell-remediation-guide#source-8)[S9](https://keendigit.com/en/insights/php2shell-remediation-guide#source-9). These are emergency deliveries for this vulnerability and do not represent a return to regular upstream support for the old branch, nor do they replace other security updates. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)

### 7.1 Take PHP 8.1 backport as an example

The relevant submissions for PHP 8.1 are:

```text
1d7dec178a094e6e75b229ce22754045f8c6070a
```

Its strategy favors fail-fast: calling `_exit(1)` after outputting diagnostics in the corresponding OOM path, and including global status and other relevant corrections; while internally disabling the corresponding processing of session upload progress. For relevant source code submission, see [S6](https://keendigit.com/en/insights/php2shell-remediation-guide#source-6).

This is a behavioral difference from the more complete delayed OOM design in the supported branch. Just because the configuration still shows that upload progress is on, it does not mean that the internal processing behavior after this backport will remain unchanged.

### 7.2 The price you need to accept when deploying

Exiting the process directly may cause the current request to fail, skipping the normal PHP shutdown callbacks and part of the application closing; if the host adopts a thread model, it is also necessary to evaluate the impact of the entire host process exit on other concurrent work. Whether the process manager can pull up the replacement process in time should also be included in the verification.

Therefore, users of older versions should consider in order:

1. Migrate to supported PHP branch and its fixed version.
2. Use a release that explicitly covers both CVE or the LTS manufacturer update.
3. If it is indeed subject to the old version of the source code, use the official emergency backport of the matching version to verify the complete changes and compatibility, and arrange subsequent migration.

The "minimum backport" here describes the compatibility and implementation scope selected by the official, and should not be automatically interpreted as "known incomplete vulnerability fixes". You should judge based on the source code of the corresponding branch and the manufacturer's announcement, and do not delete the supporting changes on your own. [S1](https://keendigit.com/en/insights/php2shell-remediation-guide#source-1)[S6](https://keendigit.com/en/insights/php2shell-remediation-guide#source-6)

## 8. Acceptance criteria and follow-up inspections

It is recommended that the following results be used as the basis for completing this repair:

| Acceptance items               | Completion standards                                                                                                                                |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| vulnerability coverage         | Build or vendor announcement explicitly fixes CVE-2026-109618 and CVE-2026-109619                                                                   |
| Deployment coverage            | All portals, pool, services and replicas use the repaired runtime                                                                                   |
| Process takes effect           | The old worker, old host process and old container all exit                                                                                         |
| Authentic request verification | Confirmed SAPI, built and configured with actual Web link to eliminate cache misdirection                                                           |
| business availability          | Key functions such as session, uploading, importing, and error handling have returned normally.                                                     |
| Ending of temporary measures   | Unlimited memory and extreme worker recycling configurations have been restored according to the capacity plan or have a clear reason for retention |
| Evidence of change             | Record package version or image digest, update scope, completion time and verification results                                                      |

The above are suggestions for implementation. If you need to verify OOM behavior, abnormal exit, or custom patches, you should use upstream regression testing or controlled fault injection in an isolated environment to avoid repeatedly creating memory exhaustion in the production environment as an acceptance method.

Also check the PHP fatal, worker crash, abnormal restart, request error rate and WAF events before and after the update. Logs can only provide investigation clues: the occurrence of OOM does not mean that it has been exploited, and the lack of alarms does not prove that no exploitation has occurred. The upgrade fixes vulnerability paths that can be reached in the future; if anomalies such as file tampering or credential leakage are found, separate incident investigations should be carried out.

## Appendix: Cited sources and links

All source links are collected below. The advisories, patches, and vendor guidance reflect checks as of **October 22, 2026**; subsequent deployments should check for vendor updates. The numbered citations in the text refer to these entries.

### S1 — PHP official security bulletin and repair version

- Source: Project PHP, October 21, 2026.
- Purpose: Risk scope, four official repair versions, official temporary measures and emergency backport instructions for old branches.
- Reference: [PHP 2026 This security bulletin](https://www.php.net/archive/2026.php#2026-10-21-5) is in the annual bulletin archive

### S2 — CVE-2026-109618 Official Technical Bulletin

- Source: php/php-src GitHub Security Advisory, October 21, 2026.
- Identification: GHSA-w8hw-w9fx-j79w.
- Purpose: Coverage boundary for OOM, multipart amplification, SAPI difference and mitigation.
- Reference: [RCE via OOM corruption](https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w)

### S3 — CVE-2026-109619 Official Technical Bulletin

- Source: php/php-src GitHub Security Advisory, October 21, 2026.
- Identification: GHSA-6wmf-4rv5-p3rp.
- Purpose: Cross-request dangling state, producers and consumers, early initialization, configuration mitigation.
- Reference: [RCE via stale global state](https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp)

### S4 — PHP 8.5 official fix submission

- Source: php/php-src.
- Submit: `31c0ea7d7ff1d1fccb6492e52dab544011628065`.
- Purpose: Confirm formal submission to fix two vulnerabilities at the same time, and explain the overall change direction.
- Reference: [Avoid state corruption via bailout](https://github.com/php/php-src/commit/31c0ea7d7ff1d1fccb6492e52dab544011628065)

### S5 — PHP 8.5 Officially restored and complete diff

- Source: diff from the same official submission.
- Purpose: Check the specific implementation of allocator, VM, HTTP globals, session, serialization and request life cycle.
- Reference: [official complete diff](https://github.com/php/php-src/commit/31c0ea7d7ff1d1fccb6492e52dab544011628065.diff)

### S6 — PHP 8.1 official emergency backport submission

- Source: php/php-src.
- Submit: `1d7dec178a094e6e75b229ce22754045f8c6070a`.
- Purpose: Check the quick exit of old branches and upload progress behavior changes.
- Reference: [PHP 8.1 Emergency backport submission](https://github.com/php/php-src/commit/1d7dec178a094e6e75b229ce22754045f8c6070a)
- Reference: [corresponds to complete diff](https://github.com/php/php-src/commit/1d7dec178a094e6e75b229ce22754045f8c6070a.diff)

### S7 — PHP 7.4 official emergency backport branch

- Source: php/php-src, PHP source code branches listed in the official security bulletin.
- Reference: [PHP-7.4-CVE-2026-109618-109619](https://github.com/php/php-src/tree/PHP-7.4-CVE-2026-109618-109619)

### S8 — PHP 8.0 official emergency backport branch

- Source: php/php-src, PHP source code branches listed in the official security bulletin.
- Reference: [PHP-8.0-CVE-2026-109618-109619](https://github.com/php/php-src/tree/PHP-8.0-CVE-2026-109618-109619)

### S9 — PHP 8.1 official emergency backport branch

- Source: php/php-src, PHP source code branches listed in the official security bulletin.
- Reference: [PHP-8.1-CVE-2026-109618-109619](https://github.com/php/php-src/tree/PHP-8.1-CVE-2026-109618-109619)

### S10 — Ubuntu Security Bulletin USN-8948-1

- Source: Canonical / Ubuntu, October 21, 2026.
- Purpose: Release backport and complete package version examples.
- Reference: [USN-8948-1: PHP vulnerabilities](https://ubuntu.com/security/notices/USN-8948-1)

### S11 — PHP-FPM Configuration Manual

- Source: PHP official document.
- Purpose: Configuration semantics such as `php_admin_value`, `php_admin_flag`, `pm.max_requests`, etc.
- Reference: [PHP-FPM Configuration](https://www.php.net/manual/en/install.fpm.configuration.php)

### S12 — PHP Core INI Configuration Manual

- Source: PHP official document.
- Purpose: Definition and scope of request body, upload, memory and automatic POST read configuration.
- Reference: [Description of core php.ini directives](https://www.php.net/manual/en/ini.core.php)

### S13 — Nginx request body size limit

- Source: Nginx official document.
- Purpose: The meaning of `client_max_body_size` and the available configuration levels.
- Reference: [ngx\_http\_core\_module / client\_max\_body\_size](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)

### S14 — Nginx FastCGI request buffer

- Source: Nginx official document.
- Purpose: The processing sequence and function of `fastcgi_request_buffering`.
- Reference: [ngx\_http\_fastcgi\_module / fastcgi\_request\_buffering](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_request_buffering)

### S15 — Nginx Condition and return instructions

- Source: Nginx official document.
- Purpose: Configuration syntax of `if` and `return`.
- Reference: [ngx\_http\_rewrite\_module](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if)

### S16 — Cloudflare PHP2Shell Protection Instructions

- Source: Cloudflare official blog.
- Purpose: Description of its WAF deployment scope, Free plan arrangement and detection mechanism.
- Reference: [Cloudflare deploys protections against php2shell vulnerability](https://blog.cloudflare.com/php-vulnerabilities-waf-protection/)

## Security maintenance consultation

Need help updating your PHP systems? We can assess exposure, plan the update and verify the running application.

[Discuss security updates](<https://keendigit.com/en/contact?service=security-remediation#form>)

[Original page](<https://keendigit.com/en/insights/php2shell-remediation-guide>) · [Content index](<https://keendigit.com/en/llms.txt>)

KeenDigit LLC · Wyoming Filing ID: 2026-002106155

[Verify with the Wyoming Secretary of State](<https://wyobiz.wyo.gov/Business/filingSearch.aspx>)

© 2026 KeenDigit LLC · Sheridan, Wyoming, USA · All rights reserved.
