TL;DR
- Pre-auth RCE in default PHP setups: PHP fixed php2shell on Oct. 21, 2026. It abuses how PHP handles out-of-memory fatal errors and works against Apache mod_php and PHP-FPM on common CMS, webmail, and e-commerce apps.
- Every secret on the host is exposed: The RCE can potentially allow attackers to read config.php and .env files using the PHP worker’s existing permissions. That gives them database, SMTP, cloud, and OAuth credentials to move into systems outside PHP.
What is php2shell and how does it work?
The root cause is how PHP handles a fatal error when a request exceeds memory_limit. The fatal error interrupts the operation in progress and leaves it half-finished: a hash table whose counters were incremented before the new bucket was initialized, or session globals still pointing into memory that request shutdown then frees. Calif turns that stale state into code execution.
Two ways to trigger the out-of-memory condition
There are two ways to trigger the out-of-memory condition.
- Bodies that skip the size check: On Apache, a chunked HTTP/1.1 or length-less HTTP/2 multipart body is never checked against
post_max_size, since PHP compares it with the declared Content-Length. - Empty file parts that skip the upload count: multipart request with hundreds of file parts using
filename="", which carry no data, are not counted towardmax_file_uploads, and still each create six$_FILESentries, combined with nested field names. The body stays under the default 8 MiBpost_max_sizewhile building$_FILESexceeds the default 128 MiBmemory_limit.
Which PHP deployments are exploitable
Both Apache mod_php and PHP-FPM are exploitable: mod_php against arbitrary scripts, PHP-FPM when the application reaches the vulnerable unserialize path. The fix is to upgrade PHP.
Why php2shell is a secrets theft vector
The RCE gives read access to everything next to the PHP code: database credentials in config.php, API keys, SMTP credentials, cloud access keys, and OAuth client secrets in .env files. No privilege escalation is needed: the PHP worker already has the permissions.
A compromised WordPress instance hands over the database, the mailer, and whatever third-party service the plugins talk to. From there, the attacker pivots to systems that have nothing to do with PHP.
Why secret rotation stalls after a PHP compromise
When the alert fires, the security team contains the server, takes forensics, and looks for persistence. The next questions are which secrets were on that machine, are they still valid, and where else are they used.
If the team does not know what secrets are deployed on the target, the list has to be rebuilt by hand from deployment scripts and Slack threads. That takes hours, and the credentials stay valid the whole time. In most remediations we see, identifying and rotating exposed secrets is manual, done from dashboard data, and starts after the compromise.
php2shell incident response: six immediate actions
Once php2shell exploitation is confirmed or suspected on a host:
- Isolate the host: Take the host off the network.
- Suspend access: Suspend user access on the host.
- Sweep other PHP hosts: Check every other PHP host for the same indicators: the attacker's source IPs and the oversized multipart requests in the access logs, new files under the web root.
- Inventory and rotate secrets: Identify every secret on the host (configuration files, environment, shell history) and rotate them in the order set by your impact mapping.
- Audit downstream access: Investigate the logs of what those secrets give access to: Kubernetes audit logs, CloudTrail for AWS keys.
- Hunt for payload execution: Look for payload execution indicators: unexpected PHP child processes, outbound connections from the web server, new files under the web root.
Step 4 is where teams lose time. A PHP host that has been running for five years accumulates credentials nobody remembers.
Prepare your secrets inventory before you need it
Step 4 takes minutes instead of hours when the following is written down before the incident, for every exposed service, PHP or not.
Perimeter knowledge
For each host: the vendors and secret types expected on it (database, cloud provider, GitLab, SMTP), the accounts they belong to (AWS account ID, Azure tenant, GitHub organization), and the domain names and machines it talks to.
Secret-to-impact mapping
For each secret: what it protects (customer data, source code, personal data, billing), and the resulting revocation order if everything on the box leaks.
Dependencies and authorities
For each secret: what breaks when it is rotated, who owns the vendor account, and who to escalate to when that person is not reachable.
Keep it next to the incident response runbook and update it when a service is deployed or decommissioned.
How GitGuardian helps with php2shell incident response

Once php2shell exploitation is confirmed, step four becomes the bottleneck: listing every secret on the host and rotating them in the right order. How fast that goes depends on whether the host was inventoried before the incident.
If the host was already inventoried
When a host has already been inventoried, NHI Governance and Endpoint Protection give responders the context they need to prioritize credential rotation:
- What the host held: every credential found on the compromised host.
- Who owns each one: the person accountable for rotating it.
- Where else it works: other hosts, images, repositories, or developer laptops that share the same credential.
- What to revoke first: a revocation order based on each credential’s criticality.
Knowing the owner is what turns “revoke the SMTP key” into a name to call at 3 a.m.
If the host was never inventoried
ggshield scans the forensic image directly, without touching the live host. With a GitGuardian API key configured, this command lists the secrets in the web root and its configuration files, including the ones that never went through a repository:
bash
ggshield secret scan path -r -y /mnt/image/var/www
The results go into the same platform, so each secret gets an owner and a rotation status like the rest of the inventory. The next incident on that host starts from the case above.
Patch PHP. Then check that you can list the secrets present on the box and who owns them.
How GitGuardian helps you to prepare for the next breach
Steps 4 and 5 are an inventory problem. The inventory is best built before an incident, but GitGuardian can also build it during the response, which is faster than running homemade scripts. To reduce exposure before the next incident and detect intrusion when it happens:
- NHI Governance builds it: it discovers the service accounts, API keys, and tokens in use across the dev ecosystem, attributes each one to an owner, scores its criticality, and flags the ones overdue for rotation under the policy you configured. The three blocks of the playbook above (perimeter, impact, dependencies, and authorities) come out of that inventory instead of a spreadsheet, and a credential that has not been rotated since the host was built shows up as overdue before anyone exploits php2shell.
- Developer Endpoint Protection feeds the same inventory from the other end of the chain. The .env and config.php that end up on the PHP host start on a developer laptop, next to ~/.aws, shell history, and MCP configuration files. ggshield runs on schedule on those machines, with no continuous agent, and reports the secrets found by machine and severity.
- Honeytokens detect intrusion. Placed in a
.envorconfig.phpon the host, they fire an alert when used. An attacker who reads the configuration after php2shell will try them.
See how NHI Governance, Developer Endpoint Protection, and Honeytokens work together on your own hosts.
FAQ
What is php2shell?
php2shell is a pre-auth remote code execution vulnerability in PHP, named by Calif and fixed on Oct. 21, 2026. It works under default configurations and abuses how PHP handles a fatal error when a request exceeds memory_limit.
How do attackers trigger php2shell?
They push a request past memory_limit in one of two ways. The first sends chunked or length-less multipart bodies on Apache, which skip the post_max_size check. The second sends hundreds of empty file parts, which skip the max_file_uploads count.
Which PHP deployments are vulnerable to php2shell?
Both Apache mod_php and PHP-FPM. mod_php is exploitable through any script, and PHP-FPM when the application reaches the vulnerable unserialize path. The fix is to upgrade PHP.
Why is php2shell a secrets theft risk?
The RCE can read config.php and .env files with the PHP worker's existing permissions. That exposes database, SMTP, cloud, and OAuth credentials, which attackers use to move into systems beyond PHP.
What should I do if php2shell was exploited on my server?
Isolate the host, suspend user access, and sweep other PHP hosts for the same indicators. Then rotate every secret on the host, check the logs of the systems those secrets unlock, and look for signs that a payload ran.
How do I find out which secrets were on a compromised PHP host?
If the host was inventoried, GitGuardian NHI Governance lists its credentials, owners, and revocation order in one query. If it wasn't, ggshield scans the forensic image to find the secrets in the web root and configuration files.
How can I prepare for the next PHP compromise?
Before an incident, document what each host uses, what each secret protects, and who owns it. Keep this next to your incident response runbook so rotating secrets takes minutes instead of hours.

