Critical PHP flaw php2shell (CVE-2026-109618)Test my domain
PHPRCECVEVulnerabilityWordPressWeb hosting

php2shell: two critical RCE flaws in PHP core

CVE-2026-109618 and CVE-2026-109619, aka php2shell: two remote code execution flaws in PHP core, rated 9.2, disclosed through a leak the day before the patch. What is established, what remains a hypothesis, who is affected, fixed versions, stopgap mitigations and a remediation plan.

by 27 min read
php2shell: two critical RCE flaws in PHP core

Why php2shell concerns just about everyone

Late on 20 October 2026, the PHP security team published an unusually terse notice: a security release would ship on Wednesday 21 October at 14

UTC to fix two critical vulnerabilities, both rated 9.2 on CVSS v4.0. No identifier, no component, no affected version. Just one instruction: get ready to upgrade the moment it is available. And one telling sentence: the team reserved the right to release earlier "should details of either vulnerability become public".

They already were, in part. A few hours earlier, a post on Hacker News had announced two RCEs in PHP, complete with the two reserved CVE numbers, CVE-2026-109618 and CVE-2026-109619, a disclosure date and a score, all resting on a "reliable source" and no evidence. The research firm watchTowr confirmed shortly afterwards that the flaws were real and under embargo. A researcher gave them a name, php2shell, and a screenshot of an exploitation tool went around. The embargo, meant to hold until Thursday, broke. PHP moved the release forward by a day.

Why this matters to your organisation, even if you think you "don't do PHP": according to W3Techs, PHP runs a little more than two out of three websites whose server-side language is known. WordPress, Drupal, Magento, PrestaShop, Nextcloud, Laravel, Symfony, hosting control panels, a good share of intranets and extranets, and a crowd of appliances embedding a PHP whose version nobody knows. A flaw in the interpreter itself, exploitable before a single line of application code runs, is a flaw in all of that at once.

This article takes stock of what is known on the morning of 21 October 2026, before the patch is published. It separates what is established from what is only a hypothesis, draws the perimeter, and details what can be done in the coming hours and the days that follow. We will update it once the official advisory is out.

The facts, as the primary sources state them

ItemValue
IdentifiersCVE-2026-109618 and CVE-2026-109619, reserved, NVD and MITRE records empty on the morning of 21 October
Namephp2shell, coined by a researcher on X, picked up by the press and by vendors
Vendorphp.net notice of 20 October 2026: two critical vulnerabilities, CVSS v4.0 9.2 each, fix on 21 October at 14
UTC
NatureRemote code execution, unauthenticated according to CERT-EU, which infers it from the score; confirmed real by watchTowr, which says it reproduced CVE-2026-109618
ComponentNot confirmed by PHP. Converging researcher hypothesis: the session extension, the upload progress handler (php_session_rfc1867_callback) and the multipart/form-data parser
Affected versionsNot published. The banner of the leaked tool claims "every release from 5.4.0"; CERT-EU relays "PHP 5 onwards"; watchTowr notes that no vendor advisory has confirmed this
Fixed versionsExpected: 8.5.12, 8.4.27, 8.3.36 and 8.2.35 (the next release of each maintained branch), unconfirmed until publication
ExploitationNo exploitation observed in the wild on the morning of 21 October (Huntress, watchTowr); not in CISA's KEV catalogue
Exploit codeA screenshot of a tool named PHP2Shell leaked on 20 October; on the morning of the 21st, GMO Flatt Security reports that exploit code is circulating. No verified public PoC

Two ways to read this table. First, everything official fits in four lines: two flaws, a score, a date, maintained branches. Everything else comes from researchers, security vendors and the leak itself. That is not nothing, several independent teams converge, but it has to be read for what it is. Second, the score: the leak said 10.0, PHP says 9.2. The two do not necessarily measure the same thing (the 10 comes from a rumour, the 9.2 from a CVSS v4.0 vector the team has not published), and the gap changes nothing about what to do.

Timeline: a disclosure in reverse

Timeline

From the notice to the leak, then to the fix

Before

  1. 24 September 2026

    Last releases before the fix

    PHP 8.5.11, 8.4.26, 8.3.35 and 8.2.34 ship, the latest version of each branch at that date.

The leak

  1. 20 October 2026, 15 UTC

    Post on Hacker News

    two PHP RCEs announced with the reserved CVE numbers, a 10.0 score and a date of 22 October, with no evidence. The post is pulled, the screenshots circulate.

  2. 20 October 2026

    Confirmation by watchTowr

    the flaws are real and under embargo. Benjamin Harris notes the release was planned for Thursday the 22nd at 11 New York time.

  3. 20 October 2026, 19 UTC

    Official PHP notice

    two critical vulnerabilities rated 9.2, fix brought forward to 21 October at 14 UTC. CERT-EU publishes advisory 2026-018 the same evening.

The race

  1. 21 October 2026, 05 UTC

    GMO Flatt Security update

    exploit code is circulating, disabling upload progress is not enough on its own. Cloudflare pushes emergency rules during the morning.

  2. 21 October 2026, 14 UTC

    Patch release

    fixed versions, affected versions and technical details expected with the security release.

Thirty-six hours between the broken embargo and the patch, during which attackers had clues and defenders had hypotheses.

The comparison that comes to mind is CVE-2024-4577, the argument injection in PHP-CGI on Windows disclosed in June 2024: Akamai observed the first attempts on its honeypots within twenty-four hours, and a ransomware crew was exploiting it within the week. That flaw only affected one specific configuration. php2shell, if the hypothesis holds, affects the default one.

What is established, what is hypothesis, what is rumour

For a flaw disclosed backwards, the hierarchy of sources matters more than usual. Three tiers.

Established. PHP's notice, relayed on oss-security and on the PHP Foundation forum: two critical vulnerabilities, 9.2, fix on 21 October at 14

UTC. watchTowr's confirmation, through its CEO Benjamin Harris: "Information has leaked wrt zero-day embargoed RCE vulns in PHP. We can confirm that they're real." The firm adds that it reproduced CVE-2026-109618 in the lab and declines to say more before the patch. CERT-EU advisory 2026-018, which recommends isolating from public networks any exposed PHP application that cannot be patched immediately.

Converging hypothesis. Several independent sources point at the same place in the code: the Session Upload Progress feature of the session extension, enabled by default since PHP 5.4, and more broadly the multipart/form-data body parser. GMO Flatt Security, in Japan, gets there through its own analysis and by reading an exploitation recording shared by a researcher. Researcher Kirill Firsov, who named the flaw, recommends disabling that feature in the meantime. A Hacker News thread speaks of "two heap use-after-free primitives" in that handler. The lead is credible, consistent with the fact that the code involved runs on every branch since 5.4, and PHP has neither confirmed nor denied it.

Rumour. The 10.0 score. The precise list of affected versions. The claim that a plain POST to any .php file is enough (plausible, not demonstrated). A very detailed anonymous write-up, with line numbers and structure offsets, circulating since 20 October: it lists 8.2.34 both as a vulnerable and as a fixed version, promises a tool with a "live target" option, and shows no verifiable result. We do not reproduce it, and we advise you not to run anything that comes from it. Booby-trapped fake PoCs are an attack technique in their own right, and days like these are their best moment.

The suspected mechanism: code that runs before yours

If the hypothesis holds, here is what you need to understand, at the level public sources describe it and without an exploitation recipe.

When a browser submits a form containing a file, it encodes the request as multipart/form-data, a sequence of "parts" separated by a boundary string. PHP reads that body very early, during request initialisation, in the handler inherited from RFC 1867: it is what fills $_POST and $_FILES before your script begins. Your application does not need to accept files, or even read $_POST, for that code to run. Any URL served by PHP receiving such a request is enough.

Grafted onto that parser, the Session Upload Progress feature has existed since PHP 5.4. Its purpose is harmless: letting a page display a progress bar during a file upload. To do so, when the form contains a field with a particular name (PHP_SESSION_UPLOAD_PROGRESS by default), PHP writes byte counters into the session as it reads the body. It is enabled by default in php.ini-production. The vast majority of applications never use it, and it is there anyway.

The technical hypothesis going around fits in one sentence: this handler would keep references to structures that another part of the processing frees, then reuse them, which makes it a heap use-after-free, the class of bug that most reliably leads to code execution when one knows how to shape memory. The recording analysed by Flatt Security points the same way: it shows memory address leaks used to defeat address space randomisation (ASLR), then a command obtained under the web server identity, www-data, in about twenty seconds, on Ubuntu 26.04 running Apache and mod_php. A second flaw, which the same sources place in the multipart parser itself, would trigger regardless of the progress setting. That is what makes the most widely quoted stopgap insufficient, and we come back to it below.

What to take away without waiting for confirmation: the attack surface is not "the pages that accept files". It is every URL served by PHP, including a maintenance page written in PHP, an empty index.php, an old forgotten info.php. And no control written in PHP runs before it: no authentication, no signature check, no application firewall coded in the framework. Sansec says it plainly for online stores: the attack hits PHP before the merchant's code and before their own application-level protection.

Kill chain

The php2shell chain, as the hypothesis describes it

Phase 1Unauthenticated multipart request (established)
  1. 1

    Any reachable .php URL

    a multipart/form-data POST is enough, with no authentication and no upload form on the page.

Phase 2Parsing before your code (established)
  1. 2

    RFC 1867 and Session Upload Progress

    PHP reads the body during request initialisation, before the script and before any application control.

Phase 3Memory corruption (hypothesis)
  1. 3

    Heap use-after-free

    references freed then reused in the progress handler and the multipart parser.

Phase 4Code execution (demonstrated privately)
  1. Shell as www-data

    address leaks to defeat ASLR, then a command, per a non-public recording.

A suspected path, not confirmed by PHP: the first links are public and documented, the final payload is not. Our scan replays none of these steps; it only reads the advertised version.

Am I affected? The perimeter, without jargon

The right question is not "does my site use uploads". It is "does any PHP answer over HTTP somewhere on my perimeter, and on which branch".

  • You expose a PHP site or application on the Internet, through mod_php, PHP-FPM, php-cgi or LiteSpeed: you are on the front line, whatever CMS or framework sits on top. The expected patch covers branches 8.2, 8.3, 8.4 and 8.5 only.
  • You run PHP 8.1 or older: no upstream release will ship for you. But "out of upstream support" does not always mean "no fix", see the note on distribution packages below.
  • You use shared or managed hosting: the host updates PHP. Your job today is to know which version serves you and to ask for their timeline.
  • You expose PHP internally only, intranet, line-of-business tool, appliance console: the risk is lower but not zero. A compromised workstation on the network, or a contractor, can reach those URLs.
  • PHP on the command line only (scripts, cron, workers): the multipart vector requires an HTTP request. That is not exposed to this flaw; update in the normal cycle.

A word on branches, because the support calendar sits at the heart of this. PHP maintains each branch for four years: two years of active support, then two years of security fixes only. As of 21 October 2026:

BranchLatest release (24 Sept 2026)End of security supportUpstream fix expected
8.58.5.1131 December 2029Yes (8.5.12 expected)
8.48.4.2631 December 2028Yes (8.4.27 expected)
8.38.3.3531 December 2027Yes (8.3.36 expected)
8.28.2.3431 December 2026Yes (8.2.35 expected)
8.18.1.x (last in 2025)31 December 2025No, out of support for ten months
8.0, 7.x, 5.xend of life2023 and earlierNo

The share of the installed base concerned is what makes this flaw different from the previous ones. Still according to W3Techs, 27% of PHP sites still run a 7.x branch and close to 8% a 5.x branch. On the server side, the Shodan survey published on 20 October by Mallory counts about 1.5 million Internet-facing hosts announcing their PHP version in their headers, 59% of them on a branch that will get no upstream fix. For France, it is a little over one host in two. Those figures count banners, not organisations, and a shared server hides hundreds of sites behind one: they give an order of magnitude, not a tally. It is enough to say that on 21 October at 14

UTC, half of the exposed PHP will have no patch to apply.

Checking your exposure without breaking anything

You do not "test" php2shell by sending a payload: with no patch published, reproducing the flaw means at best crashing a production process, at worst running code of unknown origin. Verification is therefore a matter of reading the configuration, and it comes down to three steps.

1. Know which PHP version actually answers over HTTP

The classic trap: on Debian and Ubuntu, php -v on the command line may answer for a different installation than the one serving your pages. Query the binary that really runs:

php-fpm -v                 # or php-fpm8.3 -v, php83-php-fpm -v depending on the distribution
apachectl -M | grep php    # is mod_php loaded?
dpkg -l 'php*' | grep '^ii'    # Debian / Ubuntu: exact package revisions
rpm -qa 'php*'                 # RHEL / Alma / Rocky

If you do not control the server (shared hosting), a temporary file containing <?php phpinfo(); gives the version and configuration of the web SAPI. Delete it as soon as you have read it: a forgotten phpinfo() is an information leak in itself. And look at your response headers: an X-Powered-By: PHP/8.1.2 in the HTTP response is exactly what attackers will use to sort their targets. Silencing it (expose_php = Off) fixes nothing, but it takes you out of the first wave of scans.

From the outside, a single header read without sending anything else is enough to place the version. That is exactly what our domain analysis does, and nothing more:

curl -sI https://example.com/ | grep -iE '^(server|x-powered-by):'
# Server: Apache/2.4.57 (Debian)
# X-Powered-By: PHP/8.1.2      <- advertised version, to place in the affected range

2. Read the state of the incriminated setting, on the web server side

php-fpm -i | grep -E 'session.upload_progress.enabled|file_uploads|session.upload_progress.name'

Under mod_php, read those values in the phpinfo() mentioned above: the command line often loads a different php.ini than Apache does. On everywhere is the default configuration, and therefore the most likely state.

3. List what, on your side, speaks PHP

This is the most profitable step, and the most often skipped. Not just "the website": the staging subdomains, the old blog, the phpMyAdmin behind an obscure path, the supplier extranet, the storage array console, the camera interface. Anything answering with a PHP header or a PHPSESSID cookie is in scope. External attack surface tools do this in one pass; by hand, it is a grep through your DNS zones and a visit to each host.

A word on the "detection" tools that have appeared since 20 October. One public scanner measures whether a server is reachable through the suspected code path by sending it two dozen edge-case multipart requests and counting the PHP-FPM workers that die. Its own lab produced no crash, and a "mitigated" result only means a 403 blocked the request upstream, not that PHP is fixed. Run against production, it sends abnormal traffic to a server without proving anything. We do not recommend it until the patch provides a reference to compare against.

What to do now: the remediation plan

In order of effectiveness, the only complete remediation being the fixed version.

Before 14
UTC: be in a position to patch in minutes, not days

  1. Identify the channel through which the fix will reach you. Distribution packages (and which ones: official repository, Ondřej Surý's PPA, the Remi repository), the official php Docker image or a derivative (FrankenPHP, in-house images), a hosting panel (cPanel and EasyApache, Plesk, CloudLinux and its alt-php), or a managed host. Each has its own build delay after the upstream release, counted in hours for the first and sometimes in days for the last. Knowing it now saves discovering it at 14
    .
  2. Prepare and rehearse the procedure: the update command, the PHP-FPM or Apache restart, a minimal regression test (a page that loads, a form submission, a login). On a fleet, have it scripted.
  3. Warn whoever needs warning: a PHP update in the middle of the day cuts service for a few seconds and may surface an incompatibility. Better to announce it than to suffer it.
  4. Take a snapshot (backup, VM snapshot) of exposed hosts. If a compromise happens between the leak and the patch, that is the reference state for the investigation.

In the meantime: measures that reduce the surface, not ones that close it

  • Disable upload progress tracking. In the web SAPI's php.ini: session.upload_progress.enabled = Off, then reload PHP-FPM or Apache. Without access to php.ini, a .user.ini file at the web root does the job under FPM and CGI (taken into account within five minutes at most, the user_ini.cache_ttl cache time), and a php_flag session.upload_progress.enabled off line in .htaccess under mod_php, if AllowOverride permits it. This setting cannot be set from code with ini_set(), it is too early in the request. Check the result on the web side, not on the command line.
  • Reject multipart requests where they have no business. This is the most solid measure in the meantime, because it acts before PHP, at the web server or reverse proxy level: a multipart/form-data POST to a URL that does not accept files has no reason to exist. A community kit provides the Apache rule in mod_rewrite; under nginx, an if on $content_type in the relevant location blocks does the same work. Obvious trade-off: you break file uploads on the blocked routes. List the ones that need them and block only the rest. Blocking the PHP_SESSION_UPLOAD_PROGRESS field name alone at the application firewall is finer-grained but covers only the first path.
  • Vendor application firewall rules. Cloudflare pushed two emergency releases of its managed and free rulesets on 21 October, four rules titled "Generic Rules - Anomalous Execution", in block mode. They name neither CVE nor PHP, which is normal under embargo. If you sit behind a WAF, check that those rulesets are active. And keep in mind what Sansec points out: an application-level protection sits after the point of impact, it filters known traffic, it does not fix the parser.
  • What is useless. Blocking the PHPSESSID cookie (legitimate sessions break, the parser runs anyway). Updating WordPress, Drupal or your Composer dependencies (the flaw is in the interpreter, not in the code it runs). Relying on file_uploads = Off alone: it discards the "file" parts, the body is still read.
  • Isolate what cannot be fixed. For branches with no fix and no backport, CERT-EU is clear: behind a VPN, an allow-list of addresses, or offline. An old PHP 5.6 application exposed to the public on the evening of 21 October is a matter of days, not weeks.

Concretely, to reject multipart requests outside the routes that accept a file upload, on Apache (.htaccess):

<If "%{REQUEST_METHOD} == 'POST' && %{CONTENT_TYPE} =~ m#multipart/form-data#i">
  Require all denied
</If>

And on nginx, in the location blocks with no legitimate upload:

if ($content_type ~* multipart/form-data) { return 403; }

Keep it to the paths that do not accept a file: elsewhere, you would break upload forms.

Limit what an attacker would get

Even if patched the same day, a server may have been targeted between the leak and the update. The usual defence-in-depth measures earn their keep here: a www-data user without unnecessary rights, disable_functions and open_basedir set, egress filtering (a reverse shell needs to get out), secrets that do not sit in plain text in the web tree, and logs shipped to a remote host before an intruder cleans them.

Monitor, while patching, and afterwards

There is no indicator of compromise specific to php2shell as of 21 October. Monitoring is therefore behavioural, and Huntress has drawn up the useful list: a php-fpm, php-cgi, httpd or apache2 process spawning a shell (sh, bash), an interpreter (python, perl) or a network tool (curl, wget, nc); command lines containing /dev/tcp/, mkfifo or fsockopen; reconnaissance commands (whoami, id, uname -a) run under the web server identity; new PHP files in the web root or in /tmp; unusual outbound connections. The generic "Linux webshell" Sigma rules cover most of it, and an auditd configuration on the web server UID does the rest. Add one signal specific to this flaw: a rise in PHP-FPM worker crashes (segfaults in the FPM log) correlated with multipart POSTs is exactly the trace an unreliable exploit leaves behind.

After the patch: check the version per SAPI, not only on the command line, and if a host was exposed without a stopgap between the 20th and the moment of its update, go looking. Recent files in the web root, cron jobs, created accounts, added SSH keys. And rotate the secrets reachable from the server: if an attacker got through, that is what they took.

The lesson: what runs before your code escapes your protections

php2shell, whatever its exact mechanics, is a reminder of something application teams easily forget. A whole software layer runs before the first line of your code: the web server, the SAPI, the interpreter's request parsers. Your access controls, your validations, your application firewall written in the framework never see a request that crashed PHP before reaching them. The only defence at that level is the version, and the only way to hold it is to know, at all times, what runs where.

It is also a reminder about end-of-life version debt. An unsupported branch costs nothing as long as nothing happens. The day an interpreter flaw comes out, it becomes an asset you can neither patch nor leave online, and the migration you have been postponing for two years has to happen over a weekend. A third of the PHP web is in that position this morning.

And a flaw like this one shows up neither in an application scan nor in an annual pentest dated last spring. It shows up when you map your whole information system, when you inventory your external attack surface down to the last subdomain answering in PHP 5.6, and when you know how to prioritise: a 9.2 on an interpreter present everywhere comes before everything else this week. The lesson echoes wp2shell and CVE-2026-87902 this summer: the window between disclosure and exploitation is counted in hours, and you only hold it if the inventory existed beforehand.

Detecting this kind of exposure continuously with Flawfence

At Flawfence, the principle does not change from one flaw to the next. The engine maps your Internet-facing perimeter, identifies the services answering there in your name, places their versions within known vulnerable ranges and checks the exposure of the relevant vectors, without ever sending a destructive payload.

For php2shell, let us be precise about what that means today. We do not fire the exploit, and we do not claim to remotely confirm a flaw whose vendor has not yet published the mechanism: that would be dishonest, and dangerous for your servers. What the engine already does is the other half of the problem, the one that decides everything at 14

UTC: the list of your hosts answering in PHP, with the announced branch, a flag on those that are end of life, and the admin interfaces, staging environments and forgotten subdomains speaking PHP that nobody remembers. As soon as the official advisory gives the affected and fixed version ranges, the version check will be aligned on them, as we did for each WordPress flaw this summer.

Frequently asked questions about php2shell (CVE-2026-109618 and CVE-2026-109619)

What is php2shell, in one sentence?

The name given to two critical remote code execution vulnerabilities in PHP core, CVE-2026-109618 and CVE-2026-109619, rated 9.2 on CVSS v4.0, whose existence leaked on 20 October 2026 and whose fix is published on 21 October at 14

UTC. According to the leading hypothesis, not confirmed by PHP, they live in the handling of multipart requests and of file upload progress tracking.

Which PHP versions are affected?

PHP has not published it yet. The leak claims "every release from 5.4.0", which the nature of the suspected code makes plausible, but which the vendor has not confirmed. What is certain is that the upstream fix will only ship for the maintained branches, 8.2 to 8.5. Older branches depend on backports from their distribution or their host.

Is my WordPress site vulnerable?

If the hypothesis holds, yes, like any application served by an unpatched PHP, and with no plugin or WordPress setting changing anything about it: the flaw runs before WordPress. Updating WordPress does not protect you. What matters is the PHP version serving it, hence your host's work if you are on shared hosting.

Is the flaw exploited in the wild?

Not to our knowledge on the morning of 21 October 2026: neither Huntress nor watchTowr has observed exploitation, and the flaw is not in CISA's KEV catalogue. But exploit code is circulating according to GMO Flatt Security, and the patch will reveal the bug to anyone reading the diff. Reason as if exploitation begins in the hours following publication.

Is disabling session.upload_progress enough?

No. The measure probably closes one of the two paths, it costs nothing and it is worth applying. But GMO Flatt Security corrected its recommendation on 21 October: the attack appears to remain possible with that setting alone. Do not mark any system as remediated until it runs a fixed version.

Does an application firewall protect me?

It reduces the risk, especially if it rejects multipart requests on URLs that do not need them, because that filtering acts before PHP. The emergency rules Cloudflare pushed on 21 October go in that direction. But an application firewall filters known traffic patterns and can be bypassed; it buys time, it does not replace the update.

I am on shared hosting, what should I do?

Check which PHP version serves you (in the host's panel or through a temporary phpinfo()), pick the most recent branch they offer if you are still on 7.x or 8.0, and ask them explicitly when the fixed versions will be deployed. Good hosts are communicating about it today; silence is an answer.

In summary

php2shell is the situation security teams dread: a flaw in a component present on two thirds of the web, disclosed through a leak before its patch, exploitable before any application code, and for which half of the exposed installed base cannot fix itself with a simple update. The state of knowledge on the morning of 21 October is clear on the essentials, two real RCEs and a patch at 14

UTC, and blurry on the rest, exact mechanism and affected versions.

What can be done today fits in three lines: know which PHP answers where, be ready to update within minutes at 14

UTC, and for what cannot be updated, reduce the surface now and isolate what must be. The underlying reflex remains the same as for every flaw we cover: an exhaustive inventory of what your organisation exposes, and continuous monitoring of the version of those assets. That is what Flawfence does, for PHP as for the next flaw that does not have a number yet.

Check your exposure now, it will only take you 5 minutes.

Sources

Let’s discuss your external exposure

Request a personalized Flawfence demo and discover your real exposure level.