Your login page can be flawless. Your WordPress plugins can be current. Your application can validate every input. And an attacker may still reach a critical vulnerability before your PHP code runs.
On October 21, 2026, the PHP Security Team shipped emergency fixes for two critical vulnerabilities known collectively as PHP2Shell:
- CVE-2026-109618 — remote code execution (RCE) through out-of-memory corruption during PHP request handling.
- CVE-2026-109619 — RCE through stale global state referencing memory freed after a previous request.
Both are rated 9.2/10 (Critical) under CVSS v4.0. The attacker does not need an account or a victim to click a link. Successful exploitation can run code with the privileges of the PHP web worker.
This is not a flaw in a particular WordPress plugin, Laravel controller, or Drupal module. It is in the PHP runtime itself.
The PHP team says all PHP installations serving web requests are at risk, including Apache mod_php, PHP-FPM, php-cgi, FrankenPHP, and LiteSpeed. It identifies Apache mod_php as the highest-risk configuration because a confirmed attack path can run before application-level code starts.
The fix is available now. If you operate PHP in production, treat this as an urgent runtime patch.
Article status: Based on the PHP Security Team's October 21, 2026 release and published technical advisories. See primary sources at the end.
First: is your PHP version vulnerable?
| Your runtime branch | Versions that need remediation | Minimum fixed PHP release |
|---|---|---|
| PHP 8.5 | Earlier than 8.5.12 | 8.5.12 |
| PHP 8.4 | Earlier than 8.4.27 | 8.4.27 |
| PHP 8.3 | Earlier than 8.3.36 | 8.3.36 |
| PHP 8.2 | Earlier than 8.2.35 | 8.2.35 |
| PHP 8.1 or older | End-of-life upstream | Upgrade to a supported branch, or confirm a vendor backport |
Those are the minimum fixed upstream releases, not a claim that every distribution package will report exactly those version strings. Linux distributions and commercial LTS providers can backport a security fix without changing the upstream version displayed by php -v.
Important: upgrading a WordPress theme, installing a Composer package, or updating a PHP framework does not patch PHP's C runtime engine.
🧠 Quick question: My app uses PHP-FPM, not mod_php. Am I safe?
No. PHP-FPM is in the affected population. The exact conditions and demonstrated exploit paths differ by server interface (SAPI). For example, the PHP advisory documents confirmed RCE paths for CVE-2026-109619 involving PHP-FPM under particular conditions, while the demonstrated application-independent CVE-2026-109618 path targets mod_php. Do not interpret a less exposed configuration as a patch.
Why PHP2Shell is different from an ordinary website vulnerability
A normal PHP request can be pictured like this:
Browser sends HTTP request
|
Web server / reverse proxy
|
PHP worker starts or reuses request context
|
PHP parses incoming request data
|
Application bootstrap: WordPress / Laravel / Drupal
|
Authentication, authorization, validation
|
Controller / business logic
|
Response and PHP request cleanup
The important part is what happens above the application bootstrap.
PHP must parse input, initialize internal data structures, track memory, manage sessions, and clean up after requests. Your application controls only part of that lifecycle.
With PHP2Shell, specially constructed input can reach dangerous memory states inside PHP's own request machinery. In the confirmed mod_php scenario, the exploit path can occur without the application ever getting a chance to validate that request.
That is why familiar protections such as application-level validation and authentication do not eliminate this risk.
CVE-2026-109618: what happens when PHP runs out of memory?
Root cause: an unsafe out-of-memory exit leaves partially initialized request state behind.
PHP historically used a mechanism called longjmp() to escape certain memory-allocation failures. Think of it as an abrupt jump out of the current operation.
In vulnerable code paths, that jump can occur while a request-owned structure is not fully initialized. PHP's later cleanup code may then inspect or act on the structure as though it were valid.
A conceptual model:
Request begins
|
PHP creates internal request state
|
Allocation fails at a dangerous point
|
Abrupt OOM exit skips necessary state handling
|
Request cleanup accesses invalid/partial state
|
Memory corruption -> potential code execution
The PHP advisory explains that crafted multipart request handling can cause memory use to grow in ways the initial request limits may not fully capture. The exact exploitation mechanics depend on runtime, configuration, and memory layout.
This isn't merely a denial-of-service bug. PHP reports confirmed unauthenticated remote code execution against Apache mod_php using ordinary default input and memory limits.
The released patch changes how out-of-memory failures are handled, preventing these unsafe early exits and their subsequent cleanup hazard.
CVE-2026-109619: the previous request has ended. Why is its memory still a problem?
Root cause: a long-lived PHP worker can keep a pointer to memory owned by a request that has already ended.
Imagine a worker processes two users' requests one after another:
REQUEST A SAME PHP WORKER
--------- ---------------
Temporary state is allocated
|
An error interrupts normal reset
|
Request memory is freed --------> Global pointer still refers to it
|
REQUEST B |
--------- |
Early internal operation reads --------+
stale pointer before reset
|
Use-after-free -> memory corruption / possible RCE
The key term is use-after-free: software tries to use memory after its allocation has already been released.
The official advisory describes a producer/consumer pattern. One operation leaves stale request-owned state behind; another operation, potentially on a later request handled by the same worker, touches that state before normal initialization corrects it.
Documented exposure paths involve early configuration diagnostics and session upload-progress handling. Exploitability is conditional on the PHP interface, configuration, extensions, and request sequence—but the impact can include full RCE.
Engineering lesson: request isolation cannot be assumed merely because every HTTP request has its own application context. Shared worker-process internals also have to be reset safely.
🔍 Spot the dangerous assumption
Claim: “Every request creates new PHP variables, so one request cannot affect another.”
Reality: PHP applications commonly get fresh request-scoped state, but the PHP worker process may persist across requests. Bugs in process-global engine state can cross the boundary that application developers reasonably expect to be isolated.
This is why CVE-2026-109619 is a runtime problem, not evidence of a particular application's poor coding practices.
How dangerous is it in a real production system?
A successful exploit executes within the permissions of the PHP or web-server worker—not automatically as root. That distinction matters, but it should not make anyone comfortable.
Depending on access controls and deployed permissions, an attacker with worker-level code execution may be able to:
- Read application configuration and accessible environment variables.
- Access database credentials or invoke backend services the app can reach.
- Read or change writable application files and uploaded content.
- Exfiltrate customer or business data within the worker's reach.
- Install persistence where filesystem and process controls allow it.
- Move laterally using overly broad service credentials or network permissions.
These are possible post-exploitation outcomes, not proof that every vulnerable server has been compromised.
For example, a WordPress deployment may have up-to-date plugins, but its PHP worker might still have access to database credentials in wp-config.php. A runtime RCE threatens that trust boundary regardless of plugin quality.
PHP2Shell also changes how we should think about blast radius: least privilege, read-only code mounts, limited network egress, isolated services, and short-lived credentials remain important even after patching.
Which environments should be checked?
Don't stop after checking your main website.
| Deployment | What to verify |
|---|---|
| WordPress, WooCommerce, Drupal, Joomla | Actual PHP runtime used by web requests, including managed hosting |
| Laravel / Symfony / custom PHP | PHP-FPM pools, Apache modules, workers, and every deployed environment |
| Docker / Kubernetes | PHP version inside each running image/pod, not just on the host |
Apache mod_php
|
Prioritize due to the demonstrated pre-application attack path |
| Reverse proxy + PHP-FPM | Both runtime version and configuration; proxying alone is not a fix |
| Shared / managed hosting | Provider's exact remediation status and patched build |
| CLI jobs / workers | Inventory separately; the confirmed risk focus is PHP serving HTTP requests |
Emergency upgrade guide: what to do today
Step 1 — Inventory the runtime actually serving traffic
Start with the CLI for orientation:
php -v
which php
Warning: php -v checks the CLI binary. The web server may use a different PHP installation or version.
For common Linux deployments, also inspect your running service and Apache modules:
sudo systemctl list-units --type=service --all | grep -Ei 'php.*fpm|apache|httpd|nginx'
sudo apache2ctl -M 2>/dev/null | grep -i php
ps -eo pid,comm,args | grep -E '[p]hp-fpm|[a]pache2|[h]ttpd|[l]sphp'
The Apache command is for Debian/Ubuntu-style Apache systems; commands and service names vary by distribution. Confirm the live web SAPI and version from trusted server/process configuration, host telemetry, or a restricted internal diagnostic. Do not publish a public phpinfo() page just to check a version.
Step 2 — Pick a fixed release or verified vendor backport
Use the same branch's fixed release as your emergency minimum if application compatibility permits:
- 8.5 → 8.5.12 or newer
- 8.4 → 8.4.27 or newer
- 8.3 → 8.3.36 or newer
- 8.2 → 8.2.35 or newer, then plan a supported-branch migration
PHP 8.1 and older are unsupported by upstream PHP. Some distributions and LTS providers ship security backports, and PHP has supplied limited source backports for 7.4, 8.0, and 8.1. A vendor-confirmed backport is not the same as an official new upstream maintenance release.
Step 3 — Update the deployment you really use
🐧 Debian/Ubuntu package-managed PHP-FPM
Example only for a host that intentionally runs packaged PHP 8.3:
sudo apt update
apt-cache policy php8.3-fpm
sudo apt install --only-upgrade php8.3-fpm php8.3-cli
sudo systemctl restart php8.3-fpm
sudo systemctl status php8.3-fpm --no-pager
Replace 8.3 with your deployed branch. Include the relevant PHP modules/extensions and web-server package in your maintenance change if required by your distribution.
Do not assume a successful apt upgrade means the fix was installed. Check the repository's candidate version and your Linux vendor's security advisory; an upstream version string may remain older when the vendor has backported the patch.
🐳 Docker Compose or containerized PHP
Update the Dockerfile base image or Compose image reference to a patched release from its maintainer, rebuild/pull, and redeploy the affected service:
docker compose pull
docker compose up -d --build --force-recreate
docker compose ps
If you build the PHP image locally, ensure the Dockerfile's base image is itself updated; using --build alone is not proof of a patched base. Verify the version inside the running PHP container, not on your host.
For Kubernetes, update the workload image, deploy the rollout, inspect actual pod image digests, and verify each serving replica. Old pods, rollback images, sidecars, and embedded vendor runtimes need separate attention.
🪟 Windows / IIS or managed hosting
For Windows, obtain the appropriate patched binary from the official PHP downloads page, matching the current architecture, thread-safety requirements, extensions, and web-server integration. Follow your platform's controlled deployment and restart procedure.
For hosted platforms, open the provider's PHP runtime/version controls or security advisory. Ask for confirmation that the web-facing runtime includes the fix, including any provider backport. You may not have operating-system access, so a local php -v may tell you nothing about the hosted server.
Step 4 — Restart workers and verify running versions
Restart or replace every affected worker so old processes no longer serve requests. Then check:
- The installed package/image includes the upstream fix or a vendor-confirmed backport.
- Running web workers really use that package/image.
- Each host, container, pod, and pool is covered.
- App health checks, login, sessions, uploads, checkout, and background jobs still work.
- Error rates, PHP worker crashes, memory consumption, and latency remain acceptable.
A green deploy is not a security verification. A version observed in the CLI, an image tag, or an inactive package cannot establish that every live worker was replaced.
Step 5 — Investigate, don't just patch
Review available web-server, PHP, WAF, container, authentication, and endpoint logs for unusual behavior around the disclosure window. Look for unexplained worker crashes, anomalous request volumes, unexpected child processes, modified web files, new scheduled jobs, and unusual outbound connections.
This is threat hunting guidance, not a reliable signature or proof of compromise. Absence of obvious logs does not prove absence of exploitation. If suspicious evidence exists, follow your incident-response process: preserve evidence, isolate affected workloads, and rotate exposed credentials as appropriate.
What if you cannot patch immediately?
The PHP Security Team is explicit: there is no complete configuration-only mitigation. Prioritize patching or, based on your risk assessment, isolate vulnerable internet-facing services until remediated.
The official advisory offers partial, path-specific mitigations, including:
- Disable
session.upload_progress.enabledin server-level configuration and restart all PHP workers, which blocks confirmed session-upload-progress paths for CVE-2026-109619, not every variant. - On PHP 8.5, disable
fatal_error_backtracesand restart workers; this addresses a confirmed path only. - Apply conservative
post_max_sizeand front-end request limits, including decoded size and multipart complexity, to reduce specific OOM exposure. - Review the advisory's
memory_limit=-1option only with appropriate infrastructure resource controls and operational review. It can eliminate a controllable PHP memory-limit failure, but it is not a fix and can create availability implications if handled poorly. - Avoid substituting
RLIMIT_ASorRLIMIT_DATAas a workaround; the official advisory warns that they may themselves trigger vulnerable allocation failures.
None of these measures means it is safe to leave vulnerable PHP publicly exposed. Follow the PHP team's full mitigation notes rather than copying an isolated configuration tweak.
Five myths worth killing
❌ “We don't allow users to upload files, so we're safe.”
No. The engine processes requests before application routes and policies may run. Upload-related parsing is relevant to the research, but a missing upload UI is not proof of safety.
❌ “We use Laravel / WordPress security plugins.”
Application middleware, plugins, and WAF rules are useful defense-in-depth, but they do not replace the PHP engine patch.
❌ “We are behind nginx, not Apache.”
nginx commonly forwards requests to PHP-FPM, which is included in the affected runtime population. The exploit conditions differ; the upgrade requirement does not disappear.
❌ “Our Docker host reports a patched PHP version.”
That only describes the host binary. The PHP inside your application image can be different. Inspect and redeploy the image actually serving requests.
❌ “We patched the package, so the incident is over.”
You also need to recycle workers, validate each serving instance, and review available evidence for compromise. An upgrade does not retroactively undo attacker activity.
A 10-minute response checklist for engineering leads
- [ ] Identify every public-facing PHP application and the PHP SAPI actually serving it.
- [ ] Flag all affected versions, including containers and vendor-managed installations.
- [ ] Prioritize
mod_phpwhile patching all affected SAPIs. - [ ] Deploy 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 or later, or obtain vendor confirmation of a backport.
- [ ] Replace/restart all workers; don't leave old processes in rotation.
- [ ] Run application smoke tests and monitor worker stability.
- [ ] Check logs and telemetry for suspicious activity.
- [ ] Track owners, affected services, remediation evidence, and remaining exceptions.
The architectural takeaway
There is an uncomfortable but valuable lesson here:
Your secure application still inherits the security boundary of its runtime.
Input validation protects your business logic. Authorization protects your resources. But the engine parsing a request, allocating memory, and recycling worker state is another layer of the threat model.
Patch the runtime. Verify the running worker. Reduce blast radius.
And if someone on your team still thinks a patched Composer dependency tree means the PHP server is safe, send them this article.
Discussion: What is your production PHP setup—mod_php, PHP-FPM, Docker, or managed WordPress hosting? How are you verifying the web runtime, not just the CLI version?
Primary sources (October 21, 2026)
- PHP Security Team — Emergency advisory and mitigations
- GHSA-w8hw-w9fx-j79w — CVE-2026-109618, OOM corruption
- GHSA-6wmf-4rv5-p3rp — CVE-2026-109619, stale global state
- Official PHP downloads
- Canadian Centre for Cyber Security advisory
About the Author
I write about software architecture, AI, automation, and real-world engineering challenges.
Explore more of my work and technical insights at sanukhan.dev.
Top comments (0)