PHP Security Update 2026: PHP2Shell CVSS 9.2 Fix Guide
On 21 October 2026 PHP released 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to close two unauthenticated remote-code-execution flaws. If your server, your client's server or your agency's shared hosting runs PHP, this is an upgrade-today item, not a roadmap item.
The disclosure itself was unusual. On 20 October the PHP security team published an advance notice, scheduled the release for 21 October at 14:00 UTC, and reserved the right to ship earlier. The CVE identifiers leaked a day before disclosure, along with inflated claims about severity and affected versions. Vendors had already received the patches for their distributions, and national CERTs began publishing guidance before the code was even public. In other words: nobody had a legitimate excuse for delay once the release went out.
Two Flaws, One Emergency Release
Neither bug is a logic error in an application. Both sit in how PHP prepares and tears down a request, which is why no framework update, plugin update or WAF rule substitutes for the interpreter upgrade.
CVE-2026-109618 — RCE via out-of-memory corruption. When PHP runs out of memory it aborts the request rather than continuing. The advisory describes a path where that abort interrupts PHP while internal request data is only partially initialised, so the request-cleanup step later treats invalid data as valid. An attacker who can push memory use to the limit can therefore steer what happens next. This is the flaw that makes the mitigation advice so counter-intuitive: the vendor asks administrators to stop PHP from hitting its own memory ceiling, not to tighten it.
CVE-2026-109619 — RCE via stale global state. Internal state owned by one request can survive after the memory behind it has been released. The next request handled by the same worker process may consume that stale state before normal initialisation resets it. On a long-lived worker — exactly what PHP-FPM, mod_php and LiteSpeed are — the reused memory is a normal, permanent condition, which is why this is not a corner case for exotic setups.
| Identifier | What it is | Severity | Fixed in |
|---|---|---|---|
| CVE-2026-109618 GHSA-w8hw-w9fx-j79w |
Out-of-memory handling interrupts PHP with request data partly initialised; cleanup then trusts invalid data | CVSS v4.0 9.2 | 8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 |
| CVE-2026-109619 GHSA-6wmf-4rv5-p3rp |
Request-owned state survives after its memory is freed; a later request on the same worker uses it before re-initialisation | CVSS v4.0 9.2 | 8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 |
The name PHP2Shell is not an official PHP project label; it came from researchers and security vendors and stuck, so you will see it in scanner output, hosting bulletins and CERT advisories referring to exactly these two CVEs.
Who Is Actually Exposed
The advisory is blunt: all PHP installations that serve web requests are at risk. That includes PHP-FPM behind nginx or Apache, Apache with mod_php, php-cgi, LiteSpeed and FrankenPHP. The difference between them is how much work an attacker has to do.
| Setup | Risk | Why |
|---|---|---|
| Apache with mod_php | Highest | The advisory describes a demonstrated exploit in which an unauthenticated request triggers the attack before any application code runs |
| PHP-FPM (nginx, Apache proxy) | High | Long-lived workers reuse request state; the worker usually runs as the same user as the site |
| LiteSpeed, php-cgi, FrankenPHP | High | Named in the advisory as in-scope request-serving configurations |
| Managed and shared hosting | Varies — ask | Usually patched at the platform layer, but you cannot see it; your job is to obtain the built-in version and the patch date in writing |
| Cron jobs and CLI scripts | Lower, still update | No public request surface, but they share the same binary and often hold credentials |
If you host WordPress, WooCommerce, Laravel, Magento, Magento-adjacent ERPs or any PHP booking portal for your trade business, you fall into the first three rows even when the application code is perfect. For a broader look at who should own the runtime in the first place, see our guide to IT outsourcing in Türkiye.
Check Your Version in Two Minutes
The trap here is version arithmetic. Distributions ship PHP 8.3.6 or 8.2.x for years and backport security fixes into the same visible version number, so php -v alone does not tell you whether you are protected. Compare three things.
1. The visible PHP version and the SAPI that serves traffic.
php -i | grep -E 'PHP Version|memory_limit|session.upload_progress.enabled|fatal_error_backtraces'
systemctl list-units --type=service --state=running | grep -Ei 'php|apache|nginx|litespeed'
2. The distribution package version, not the upstream one. On Debian and Ubuntu the changelog is the honest answer; on RPM systems query the package changelog.
zcat /usr/share/doc/php8.3-cli/changelog.Debian.gz | grep -iE 'CVE-2026-10961[89]'
apt-cache policy php8.3-fpm | head -4
# RPM-based hosts
rpm -q php && rpm -q --changelog php | grep -iE 'CVE-2026-10961[89]'
If the changelog mentions both CVEs in the installed version, you are patched even though php -v still says 8.3.6. That is the difference between a real security answer and a version-number superstition.
3. Whether the running process reloaded the patched binary. A package update that is never followed by a restart leaves the old code in memory. Compare the service start time with the package install time:
stat -c '%y %n' /usr/sbin/php-fpm8.3
On cPanel, Plesk, DirectAdmin or a managed platform the equivalent is the PHP selector plus the host's own security bulletin: identify the built-in version your site is actually assigned, not the newest one advertised in the panel. If your host cannot state a patch date, treat the site as unpatched. Our digital infrastructure services cover this audit plus the upgrade itself; you can also simply contact us with your stack and we will tell you what we would check.
Fixed Versions and the EOL Cliff
PHP supports a branch for two years of active development and two further years of security fixes. That policy is what produced four simultaneous fixes on 21 October — and it is also what leaves older branches on their own.
| Branch | Fixed release | Status after this advisory |
|---|---|---|
| PHP 8.5 | 8.5.12 | Actively supported |
| PHP 8.4 | 8.4.27 | Actively supported |
| PHP 8.3 | 8.3.36 | Security-support phase |
| PHP 8.2 | 8.2.35 | Security support ends 31 December 2026 — plan the jump now |
| PHP 8.1 and older | No upstream release | Vendor backports only; the PHP project published minimal source backports for 7.4, 8.0 and 8.1 for those who build from source |
Two practical warnings from the advisory. First, if you install PHP from a community repository rather than your distribution, that repository may lag the security window: the maintainers of the widely used Remi packages stated they would not have same-day updates, so the safe path is your distribution's packages or a source build. Second, if you are on PHP 8.1 or older, "waiting for our host" is a security decision you are making on behalf of your customers — document it or change it.
Patch a Production Server Without an Incident
Same-minor security updates rarely break an application; untested restarts do. The order below is what we use on live trade platforms, and it keeps the risk window short without gambling the site.
- Snapshot first. A hypervisor or volume snapshot you have actually tested restores in minutes, and it makes the decision to patch cheap.
- Reproduce the version in staging. Same branch, same extensions, same PHP configuration files, a copy of production data. Run the checkout, quote-request and payment paths, not just the homepage.
- Upgrade the package set as a unit. Mixing an upgraded CLI with an old FPM binary is how people end up with a patched
php -vand an unpatched web path:apt-get update && apt-get install --only-upgrade 'php8.3-*', ordnf update --security 'php*'on RPM hosts. - Restart the request-serving process, then verify it restarted.
systemctl restart php8.3-fpm(or reload Apache / restart LiteSpeed), then re-check the service start time and run the version and changelog queries again. - Watch the error log for one hour. OOM messages, new fatal-error signatures and unusual 5xx rates are the signals that the mitigation settings below may need tuning — not reasons to postpone the upgrade.
- Record the evidence. Package version, changelog line mentioning both CVEs, restart timestamp. Clients, auditors and ISO 27001-style control reviews all ask for exactly this, and it takes ten seconds to save.
Where the upgrade must wait — a validated ERP integration, an embargoed release calendar, a client sign-off loop — put a compensating control in front of it the same day rather than leaving the port open and hoping. That is what the advisories from national CERTs recommended for exactly this situation: isolate internet-facing PHP applications from the public network where immediate patching is not possible.
Temporary Mitigations: Narrow the Window, Do Not Close It
The PHP advisory states plainly that there is no complete mitigation and that updating is the only safe choice. Treat the following as days-not-weeks cover, applied at a level the application cannot override, with every worker restarted afterwards.
Against CVE-2026-109618 (the out-of-memory path)
- Let PHP exhaust the machine's memory instead of its own limit:
memory_limit = -1, ideally asphp_admin_value memory_limit = -1so application code cannot put the ceiling back. - Keep request bodies small at the interpreter: the advisory's guidance is around 8 MB when there are no uploads and around 32 MB when there are, with
upload_max_filesizebelowpost_max_size. - Enforce the expensive limits at the proxy, because the damage is in the decoded request, not the wire size: total decoded body size, number of input fields, number of multipart parts, number of headers, nesting depth — and cover requests that arrive without a usable
Content-Length. - Contain the blast radius with a container or cgroup memory limit sized so that a killed worker is an availability event, not a host event. Do not substitute
RLIMIT_ASorRLIMIT_DATA: those trigger the very allocation failure that is in the vulnerable path.
Against CVE-2026-109619 (the stale-state path)
- Disable session upload progress with
session.upload_progress.enabled = 0, set in php.ini, the FPM pool or server config — somewhere that applies before request parsing. Then restart every worker, because FPM shares already-initialised module state between requests.ini_set()and.user.iniare too late to help. - On PHP 8.5, set
fatal_error_backtraces = 0and restart. - Remove per-request settings that are invalid or deprecated and therefore emit diagnostics during early initialisation. Suppressing the message with
error_reporting,display_errorsor@does not remove the code path. - Hunt attacker-reachable fatal errors and long-running timeouts in upload and import handlers, callback code and cleanup routines — the same places both bugs live.
A CDN or WAF in front of the origin still earns its keep: rate limiting, blocking anomalous request shapes and virtual patching reduce noise and slow opportunistic scanning. They are a speed bump for a targeted attacker, not a control you can sign off as remediation.
What to Ask Your Hosting Provider Today
Support scripts answer this question with "we are always patched". Ask instead for evidence you can file:
- The built-in PHP version assigned to our account, and whether it is a distribution package or a vendor build.
- The date the CVE-2026-109618 and CVE-2026-109619 fixes reached your fleet, with the internal package version string.
- Whether the fix applies to the SAPI serving our site (FPM, LiteSpeed, mod_php) and to any staging or backup node we might restore.
- If the platform is not yet patched: what compensating control is in place and until when.
- Your standing policy for EOL branches — what happens to my site on 1 January 2027, when PHP 8.2 security support stops.
A provider that answers those five questions in one email is a provider worth keeping. One that circles back with marketing copy is a migration conversation; the same diligence applies as in our ISO 27001 gap assessment work, where the deliverable is evidence, not reassurance.
Should You Assume You Were Compromised?
Not automatically — but check rather than guess, especially if the server was exposed to the public internet during the window before your patch.
- Look for processes, listeners and cron entries you did not create, and for outbound connections from the PHP worker user.
- Diff writable application directories against a deploy source of truth: new PHP files, modified upload directories, unexpectedly executable temp folders.
- Search web logs for request storms around the disclosure hours, unusually large multipart bodies, or requests that returned 500 with OOM signatures in the PHP error log.
- Check that the patched binary is actually running — the restart-time comparison above answers it.
- If anything looks wrong, treat it as an incident: preserve the disk and logs, rotate every credential the application can read, and rebuild from a known-good image. Reinstalling the PHP package over a compromised host is not remediation.
A Worked Example From Our Own Infrastructure
We run worldwidetradex.com on Ubuntu 24.04 LTS with nginx and PHP-FPM, so we ran the checks above on ourselves on 22 October. The results are a good illustration of why version arithmetic matters:
php -v reported PHP 8.3.6 — a number that, read against upstream PHP, looks three years stale and alarming.
dpkg -l reported 8.3.6-0ubuntu0.24.04.13, and the packaged Debian changelog for that exact version lists CVE-2026-109618 and CVE-2026-109619 with the vendor patch applied. apt-cache policy showed the installed version equal to the candidate, so nothing newer was pending.
Conclusion: patched through the distribution backport, served by PHP-FPM rather than mod_php, with the FPM service restarted after the package update. Same exercise, five commands, and we can show the evidence to a client who asks.
The lesson transfers to any stack: your security posture is the package version plus the changelog plus the restart, not the marketing version string in the hosting panel.
Make Patching Routine Instead of Heroic
PHP2Shell is not memorable because it is exotic; it is memorable because the interpreter that most of the web runs on had a critical, pre-authentication bug and thousands of hosts had to react within hours. The teams that slept through it were not lucky — they had automation.
- Unattended security upgrades for the interpreter, with the version and restart recorded automatically.
- An inventory that knows which SAPI and which PHP branch every site uses, including staging, backups and that one WordPress from 2019.
- A rehearsed restore path, so "patch now" is never weighed against "we cannot roll back".
- A branch plan: nothing on a PHP release whose security support ends inside the next twelve months.
- One named owner per server and a written escalation route for the days a patch lands at 14:00 UTC on a Wednesday.
If you would rather buy that capability than staff it, we take ownership of production PHP platforms — patch cadence, monitoring, backups and documented restores — as part of our managed infrastructure work. Start with a short brief and quantities: request a quote.
Frequently Asked Questions
Is my website definitely hacked if it runs an unpatched PHP version?
Not necessarily. An unpatched, internet-facing PHP installation is exposed, and scanning began around the disclosure, but exposure is not compromise. Patch first, then run the verification steps above; only treat the host as compromised on evidence, and rebuild rather than clean if you find any.
My host says PHP 8.3.6. Is that patched or not?
It depends on the build. Distribution packages carry the CVE fixes while keeping the upstream version number, so PHP 8.3.6 from Ubuntu 24.04 or Debian can already include both fixes. Ask for the full package version and the changelog line that names CVE-2026-109618 and CVE-2026-109619; on managed platforms ask for the patch date instead.
Do plugin, theme or framework updates protect me from PHP2Shell?
No. Both flaws are in the PHP interpreter's request setup and teardown, not in application code. Application updates remain good hygiene, and a WAF slows opportunistic traffic, but only the interpreter upgrade removes the vulnerability.
Can I just set a lower memory limit to block the out-of-memory bug?
The opposite. The advisory's interim guidance for CVE-2026-109618 is to stop PHP aborting on its own memory ceiling — memory_limit = -1, set so application code cannot override it — then cap request complexity at the proxy and contain the worker with a container or cgroup limit. A tighter PHP limit sits inside the failure mode being exploited.
We are on PHP 8.1 or older, which got no upstream release. What now?
Move to a supported branch if you can; that is the durable answer. If you cannot, take the fix from your distribution or vendor, which is the only realistic source, or apply the minimal source backports the PHP project published for 7.4, 8.0 and 8.1 if you build from source. Record that decision, because it changes your risk profile every month you keep it.
Is upgrading PHP 8.3 to 8.3.36 risky for a live store?
A same-minor security update changes the interpreter binary, not the language, so most applications are unaffected. The risk is operational: partial package sets, a forgotten restart, or a configuration that only shows up under load. Snapshot, upgrade the whole PHP package set, restart the request-serving process and verify — and do it on staging first when the platform is complex.
Sources
- PHP — security advisory "Critical remote code execution vulnerabilities, update now" and the 21 October 2026 release announcements, including the mitigation guidance and the support timeline on supported versions.
- GitHub Security Advisories for the PHP repository: GHSA-w8hw-w9fx-j79w (CVE-2026-109618) and GHSA-6wmf-4rv5-p3rp (CVE-2026-109619).
- CERT-EU — Security Advisory 2026-018, "Critical Vulnerabilities in PHP", naming both CVEs.
- Infosecurity Magazine — "Critical PHP Vulnerabilities Leaked Ahead of Scheduled Security Patches" (21 October 2026) and "PHP2Shell Exploitation Attempt Detected by Amazon Four Days Before Vulnerability Disclosure" (22 October 2026).
Need the upgrade handled for you? To discuss patching, a version audit, migration to a managed and patched PHP platform or the infrastructure around it, contact us or call +90 505 679 78 03.