Skip to main content
Security alertPHP2Shell: critical PHP flaw — WordPress updates can't fix itCheck your PHP version
WP HealthKit

PHP2Shell: the critical PHP flaw that WordPress updates can't fix

October 23, 202622 min readSecurityBy Jamie

On 21 October 2026, the PHP project shipped emergency updates for two critical vulnerabilities in PHP itself. Not in WordPress. Not in a plugin. In the language your site is written in, on the server your host runs.

The flaws are tracked as CVE-2026-109618 and CVE-2026-109619, and the pair has been nicknamed PHP2Shell. Both are rated 9.2 out of 10 under CVSS v4.0. Under the right conditions, an attacker with no account, no password and no access to your admin can run their own code on the server.

That means the usual advice — "update your plugins, update WordPress" — does not help here. There is no WordPress update coming for this, and there doesn't need to be. The fix lives one layer below WordPress, and on most sites someone else controls it.

This guide is the plain-English version: what actually happened, who is exposed, how to check your own site in two minutes, what to do about it, and what the Cloudflare mitigation genuinely protects you from.

What happened

PHP normally releases security fixes on a set schedule. This one came a day early, at 14:00 UTC on Wednesday 21 October, after details began leaking online.

The vulnerabilities were reported to the PHP security team in August 2026. The first was found by researcher Ryan Austin, working as part of OpenAI's Patch the Planet initiative; Wiz Research independently found and reported both, and Quarkslab is also credited in the disclosure. Everyone involved was working to a coordinated release date when the CVE identifiers leaked, an exploit video surfaced, and Chainguard published patched container images ahead of schedule. The PHP project pulled the release forward rather than leave the window open.

The PHP Foundation has since acknowledged that a core developer first spotted signs of the underlying problem back in 2024, and that work on a fix stalled for months. It called the delay "a structural failure". That's worth sitting with: the bug is not new, and neither is the lesson about how long "we'll get to it" can last.

According to Cloudflare, the flaws affect every web server running PHP 5.4 or later — which is most of the internet, since PHP underpins roughly 70% of websites. The WordPress security team was blunt about the scope: these vulnerabilities are "not specific to WordPress" and affect any server hosting a PHP application.

The bug, in plain English

Here's the mental model that makes this click.

When PHP handles a request — a page view, a form submission, an API call — it sets aside a patch of memory as a workbench, does the job, then tidies up and hands the workbench back. That tidy-up step is supposed to happen every single time.

The researchers found that if a request fails partway through, the tidy-up doesn't happen properly. Memory gets released while PHP still holds a reference to it. Because PHP keeps processes alive to serve many requests in a row, a later request can reach the leftovers of an earlier one.

If an attacker carefully shapes what's left on that workbench, they can steer PHP into following their instructions instead of yours. That's the "shell" in PHP2Shell: control of the server, not necessarily a literal command prompt.

VulnerabilityWhat goes wrong
CVE-2026-109618PHP runs out of memory mid-request and is interrupted before some internal data is properly set up. During cleanup it treats that unfinished data as if it were valid.
CVE-2026-109619A fatal error interrupts a request, leaving PHP holding references to memory that is freed when the request ends. A later request reuses that process and follows the stale references into memory it no longer owns.

Neither bug needs a login. Neither needs a vulnerable plugin, a weak password, or a misconfigured setting. The attack surface is "PHP answered an HTTP request", which is the definition of a website.

Why this is different from a normal WordPress vulnerability

Most WordPress security stories are about a plugin. Someone finds a missing capability check in a form handler, the vendor ships a fix, site owners click Update, and the story ends. This one breaks that pattern at every step.

Typical plugin vulnerabilityPHP2Shell
Where the bug livesA plugin or theme you installedThe PHP runtime underneath everything
Who can fix itThe plugin authorYour host, or you if you run the server
Does updating WordPress help?OftenNo
Does a security plugin help?OftenNo — it's below that layer
What an attacker getsOften one feature, one siteCode execution as the web user, potentially the whole server
How many sites affectedHundreds to millions, depending on the pluginAny server on an unpatched PHP version

That last row is why this feels different. A plugin vulnerability is a door left unlocked. This is a flaw in the lock design itself, on a building shared by most of the neighbourhood.

Your site is only as patched as your host. For the first time in a while, "which host are you on, and what exactly are they running?" is the most important security question a WordPress site owner can ask.

Who is exposed right now

Being on "managed WordPress hosting" is not, by itself, an answer. What matters is whether the PHP binary serving your requests is on a fixed version, and whether the host applied a firewall mitigation while they rolled it out.

Here's the honest shape of the risk as of 23 October 2026:

  • Large managed hosts moved fast. Automattic said WordPress.com, WordPress VIP, WP Cloud and Pressable were protected ahead of the release. SiteGround, WP Engine, Kinsta, Hostinger and 20i reported mitigations followed by patches; Bluehost and GoDaddy reported a mix of patched servers and mitigation-only servers at various points. Status pages are the place to check, not marketing pages.
  • Self-managed servers are yours. VPS, dedicated boxes, cPanel accounts you administer, and anything you installed PHP on yourself. Nobody is coming to patch it for you.
  • Containers are a trap. If your site runs in Docker or Kubernetes, the host kernel being patched doesn't help. Your image has to be rebuilt on a fixed PHP base and redeployed, or old containers keep serving the vulnerable binary.
  • Multiple PHP versions per account. Shared hosts and cPanel setups often let one account run several PHP versions, and an old one can still be selected for a subdomain, staging copy or cron job. Patch all of them, not just the one the main site uses.
  • Staging and dev copies. The forgotten clone on a public URL is as exploitable as production, and usually less monitored.
  • Older PHP is a separate problem. Roughly 35.1% of WordPress sites were reported to be running a PHP version the project no longer patches. For 7.4, 8.0 and 8.1 the PHP security team published minimal source backports rather than full releases. Below that, there is no official fix at all.

Check your PHP version in two minutes

Start with the check that reflects what your web server is actually running, not what a terminal happens to have installed.

Option 1 — inside WordPress (best for most people). Go to Tools → Site Health → Info → Server and look for the PHP version. If you can't get into wp-admin because the site is down, that's a different emergency.

Option 2 — your hosting panel. cPanel, hPanel, Plesk and similar show the PHP version per domain, and often let you switch it. Check every domain and subdomain listed, not just the primary one.

Option 3 — WP-CLI. If you have shell access to the site:

wp eval 'echo PHP_VERSION;'

Option 4 — terminal, with a caveat. php -v tells you what the command line uses. On many servers the CLI and the web process (PHP-FPM) are different builds, sometimes different major versions. Treat it as a hint and confirm through Site Health or your panel.

Option 5 — containers. Check the image tag and what the running process reports:

docker compose exec php php -v

Then rebuild from a fixed base image and redeploy. A restart alone keeps the old binary.

What "patched" looks like

PHP branchFixed versionStatus
8.58.5.12Supported
8.48.4.27Supported
8.38.3.36Supported
8.28.2.35Supported, but reaches end of life 31 December 2026
8.1, 8.0, 7.4Minimal backports onlyUnsupported — plan the upgrade
Earlier than 7.4NoneUnsupported and unfixable

If you're on 8.2, patching now buys you a few months. Use them to move to 8.3 or newer, because after 31 December there will be no more security releases for that branch at all.

What to do, in order

1. Patch PHP — this is the only real fix

Update the package, then make sure the running processes are using the new code:

# Debian/Ubuntu example — adjust the version to yours
sudo apt-get update
sudo apt-get install --only-upgrade php8.3-fpm php8.3-cli
sudo systemctl restart php8.3-fpm

A few details people miss:

  • Restarting matters. PHP-FPM keeps worker processes alive. Updating files on disk without restarting the service can leave vulnerable workers serving traffic.
  • Patch every installed version, including ones you don't think are in use. Then remove the ones you don't need.
  • Rebuild containers and redeploy. docker compose up -d --build, or a fresh rollout in Kubernetes. Don't just restart.
  • Clear opcache if your setup caches compiled PHP aggressively.
  • Verify after. Re-check Site Health or your panel and confirm the version changed. "We ran the update" and "the site is now serving 8.3.36" are different claims.

If your host manages PHP, you don't run these commands — but you can still ask for the version number in writing, and you can still check Site Health yourself.

2. Keep the firewall on — but understand what it is

Cloudflare deployed WAF rules for these vulnerabilities before public disclosure — about nine hours ahead — and turned them on by default for free and paid plans from 03:02 UTC on 21 October. That's a genuinely good piece of defensive work, and if your site is behind Cloudflare, you were covered while you worked out your patching plan.

What's actually protecting you:

  • Seven managed rules for the two CVEs, split across the free and paid rulesets.
  • Full transaction detection, a new Cloudflare capability that looks at the request and the origin's response in the same transaction. That matters because this bug's fingerprints are often in how PHP responds, not just in the request, and it lets the firewall block a matching response before it reaches the attacker while keeping false positives down.
  • Default-on deployment. Free plans use the Cloudflare Managed Free Ruleset (ID 77454fe2d30c4220b5701f6fdfb893ba); paid plans use the Cloudflare Managed Ruleset (ID efb7b8c949ac4650a09736fc376e9aee).

A short checklist:

  1. Confirm your DNS is proxied. Cloudflare can only filter traffic that passes through it. A grey-clouded record, or a subdomain pointing straight at the origin, is unprotected.
  2. Confirm the managed ruleset is deployed in Block mode. Paid plans: Security → Security Rules → Managed Rules. Free plans: it's on by default; check that nobody disabled it.
  3. Check the response-side rules are active. Security → Security Rules should show the Managed Response Firewall default deployed.
  4. Look at what's being blocked. Security → Security Analytics → Events, filtered by the PHP2Shell rule IDs, shows attempts against your site. That's useful both as a signal and as evidence for your host.
  5. Don't disable managed rules to silence a false positive. Narrow the scope or handle the exception specifically; turning the ruleset off removes protection for everything.

Cloudflare isn't the only option — Fastly, Sucuri, your host's own edge, and a properly configured origin firewall all help — but the principle is the same. Filtering is a bridge. Patching is the destination.

3. Reduce exposure while you're patching

These don't fix anything. They narrow the window.

  • Cap upload sizes. Large requests are one way to put the memory pressure these bugs feed on. Bluehost warned customers to expect upload limits for exactly this reason.
  • Disable upload endpoints you don't use. Any handler that accepts files and parses them is worth questioning.
  • Take a snapshot first. Before you change PHP versions on a live site, make sure you can roll back. PHP upgrades break old plugins; you want a way out that isn't a restore-from-yesterday.

4. Then go looking for damage

Attacks started before the patches shipped, so "I'm patched now" doesn't mean "I was never hit". Wordfence recommends keeping server and firewall logs covering at least 48 hours before the release.

Look for:

  • PHP files in uploads/, cache/, or other directories that should never contain executable code.
  • Files with recent modification times that don't match a known update.
  • Unknown administrator users, or new users with elevated roles.
  • Unexpected scheduled tasks (WP-Cron events and system cron entries).
  • New or modified .htaccess rules that route traffic somewhere odd.
  • Outbound connections from the web server to hosts you don't recognise — a common sign of a payload phoning home.
  • Odd processes under the web user, especially anything spawning a shell.

On the detection side, Wordfence's researchers were candid: they achieved code execution for one vulnerability in a specially configured lab, while the same test only crashed a standard PHP build, and the second vulnerability mostly caused PHP failures in their WordPress tests. Attacks may need tuning per server. Their conclusion is the one to keep: an unpatched server should not be considered safe just because a public proof-of-concept didn't work against it.

If you think you were compromised

The memory bug gives an attacker the ability to run code. It does not by itself persist. Persistence is whatever they upload or change afterwards — usually a webshell, a modified core file, a rogue admin user or a scheduled task.

That's why deleting the suspicious file is not incident response:

  1. Preserve evidence before you clean. Copy logs, file listings and timestamps somewhere safe.
  2. Assume the application is untrusted. Reinstall WordPress core, plugins and themes from official sources, and compare against known-good checksums.
  3. Rotate everything that lived on that server: WordPress salts and keys in wp-config.php, database credentials, API keys stored in plugins, SMTP and payment credentials, SSH keys, and any tokens in environment variables.
  4. Audit users and roles, including hidden and multisite-level accounts.
  5. Review outbound traffic and cron for anything you didn't create.
  6. Tell people if customer data may have been exposed. In the EU and UK, breach notification clocks are short.

We wrote a fuller walkthrough in WordPress malware recovery: cleanup and hardening, and there's a preventive checklist in the 2026 WordPress plugin security checklist.

What this means for the wider WordPress ecosystem

Four things stand out.

1. The runtime is the shared floor. WordPress can ship excellent security releases and plugin authors can write flawless code; none of it matters if the language underneath is exploitable. The WordPress project can't patch this, plugin authors can't patch this, and security plugins are explicitly the wrong layer. The responsibility sits with hosts and sysadmins, and site owners need to know that so they can ask the right question.

2. Hosting has become a security product again. The hosts that came out of this well did the same things: mitigated before the patch was public, communicated on a status page, and patched methodically. The ones that struggled weren't necessarily careless — some were waiting on vendor packages — but they left customers guessing. "Managed" should mean "we will tell you what version you're on and when it changes."

3. The disclosure process bent. CVE IDs leaked, an exploit video appeared, patched container images landed in registries hours early, and the release date moved. The PHP Foundation has been unusually direct about both the delay and the leak. The uncomfortable takeaway for everyone in the ecosystem: embargoes are only as strong as the largest number of people holding the secret, and "we'll fix it next quarter" is a decision with a date on it.

4. Expect the aftermath to look like plugin malware. Mass exploitation of a PHP RCE rarely produces a dramatic defacement. It produces webshells, SEO spam, redirects and — on WooCommerce stores — card skimmers. If you run a store, treat any unexplained checkout JavaScript as a possible post-exploitation artefact, not a theme bug. Our guide to WooCommerce payment gateway security covers where skimmers usually hide.

The longer lesson: never guess your PHP version again

This incident will be patched out within weeks. The pattern behind it won't be.

Every WordPress site in existence sits on a stack where at least one layer — the runtime — is maintained by someone other than the person who owns the site. Most owners cannot answer, without logging in, which PHP version they're on or who is responsible for updating it. That gap is the actual vulnerability, and it's the one you can close permanently.

Three things worth putting in place now:

  • An inventory. For every site you're responsible for: host, PHP version, who patches it, and where the status page lives. A spreadsheet is fine. Not having one is not.
  • A runtime patch SLA. Plugin updates usually get a policy. PHP rarely does. Decide how fast a critical runtime patch gets applied, and write down who does it.
  • A way to notice drift. PHP versions change without anyone deciding to change them — a host migrates a server, an image tag floats, a staging copy gets restored from an old snapshot. Alert on the version, and on end-of-life dates, before they become an incident.

If you build plugins or themes, there's a role here too: state the PHP versions you actually support and test against them, including 8.3, 8.4 and 8.5. Don't leave users guessing whether your code runs on a patched runtime. PHP 8 compatibility for WordPress plugins is the starting point.

Frequently asked questions

Do I need to update WordPress? No. The WordPress security team confirmed no core update is required or planned for these issues. Updating WordPress is still good practice, but it will not fix PHP2Shell.

Will Wordfence, Sucuri, Patchstack or my security plugin fix it? No. Those tools operate inside WordPress or at the edge. This bug is in the PHP runtime, below the layer they can patch. They can help you detect exploitation and block some attempts; they cannot install a new PHP.

Is Cloudflare's WAF enough? No. It's a mitigation that was deployed before disclosure and covers free and paid plans by default, which is genuinely valuable. But Cloudflare describes it as a stopgap, and the only reliable fix is patching PHP. Keep the WAF on and patch.

My host says I'm protected. Am I done? Ask for the version number. "Protected" can mean patched, or it can mean "behind a WAF while we wait for packages". Both are better than nothing, but only one is a fix.

I'm on PHP 7.4. What are my options? The PHP security team published minimal backports for 7.4, 8.0 and 8.1, and some hosts applied them. That's a bridge, not a destination — those branches get no further security releases. Upgrade to 8.3 or newer. If you manage the server yourself and can't upgrade quickly, the published guidance is to consider taking it offline.

Can an attacker get in through a plugin? They don't need to. PHP2Shell is triggered by crafted HTTP requests reaching PHP, which every page view does. A vulnerable plugin is a separate, additional risk, not a prerequisite.

Does this affect WooCommerce stores? Yes, if the server is unpatched. Code execution means the attacker can read your database, modify checkout JavaScript, or add an admin user. Store owners should check their PHP version with the same urgency as everyone else, and check for injected scripts if they were exposed.

Should I take my site offline? Only in the specific case the guidance describes: you manage your own server, you're on PHP earlier than 8.2, and you can't patch quickly. For everyone else, patch and keep the firewall on.

How do I know if my site was attacked? You may not, from the site alone. Check firewall analytics for blocked PHP2Shell rule hits, review server logs from 48 hours before the release, and look for the file and user anomalies listed above. Absence of a blocked hit in your logs doesn't prove you were untouched if you weren't behind a filtering layer.

Will there be more of these? Assume yes. The same research programme that found this one is actively looking for more, and the 2024-to-2026 gap shows how long a known-but-unfixed issue can sit. Build the habit of tracking your runtime, not just your plugins.

Sources and further reading

This is a fast-moving incident. We'll update this guide as hosts publish patch status and as the PHP project ships follow-up releases. Last checked 23 October 2026.

Ready to audit your plugin?

WP HealthKit checks for all the issues in this article and 40+ more across 62 verification layers.

Comments