PHP2Shell (CVE-2026-109618 and CVE-2026-109619): critical PHP vulnerabilities and what to do

Two critical PHP vulnerabilities allow unauthenticated code execution on WordPress, Joomla, Drupal and any other PHP application. Affected versions, updates, temporary mitigations and how to check a server for signs of attack.

OfSec 7 min read

On 21 October 2026 the PHP team released fixes for two critical vulnerabilities in the language itself, known as PHP2Shell. They let an outsider with no username or password run code on the server that hosts a website. Practically every PHP version since 5.4 is affected, and with it every site built on WordPress, Joomla, Drupal, Magento, PrestaShop, OpenCart or any other PHP application.

In short

  • CVE-2026-109618: memory corruption when the memory limit is exhausted (out-of-memory).
  • CVE-2026-109619: use-after-free through internal state left over from a previous request.
  • CVSS 4.0 score: 9.2 out of 10 for both.
  • Fixed versions: 8.5.12, 8.4.27, 8.3.36 and 8.2.35.
  • PHP 8.1 and older receive no official fixes.
  • Exploitation attempts against both vulnerabilities are already being seen on the internet.

Which sites and servers are affected

According to PHP's official announcement, every installation that serves web requests is at risk: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. The risk is highest with mod_php, where a single request can trigger the attack before any of the site's code runs. Researchers at Wiz, among those who found the vulnerabilities, have demonstrated unauthenticated code execution against WordPress, Drupal and Joomla. The flaws are in PHP itself, so no bug in the site's own code is needed.

PHP version Status
8.5 fixed in 8.5.12
8.4 fixed in 8.4.27
8.3 fixed in 8.3.36
8.2 fixed in 8.2.35; support ends on 31 December 2026
7.4, 8.0, 8.1 no official release; only source patches for manual builds and packages from some distributions and long-term support vendors
5.4 to 7.3 no fix

If your site runs PHP 7.4, 8.0 or 8.1, the only reliable solution is moving to a supported version.

How the vulnerabilities work

PHP handles each request in a worker process, which then serves further requests. Both vulnerabilities exploit moments when PHP aborts abruptly and does not clean up memory completely.

CVE-2026-109618: memory exhaustion

When a request exceeds the memory limit (memory_limit), PHP stops processing it immediately. If that happens while the request's internal data is only half prepared, the cleanup code treats it as valid and works with uninitialised memory. The attacker causes the memory exhaustion with a specially crafted multipart request, for example with many headers in a single part or many empty file fields. Such a request can stay under the post_max_size limit while taking up many times more space in PHP's memory.

CVE-2026-109619: state left over from a previous request

After a fatal error or memory exhaustion, some global pointers keep pointing to memory that has already been freed. The next request to the same worker can read that memory before PHP resets it. The researchers have shown that this leaks memory contents into the PHPSESSID cookie of the response, and that on PHP 8.5, combined with other techniques, the attack leads to code execution. On its own, the vulnerability leaks data from other requests: passwords, API keys and sessions.

The scores for both vulnerabilities assume high attack complexity: the attacker has to control memory layout, and the result depends on the version and configuration. Once written, however, such an exploit can be used at scale against thousands of sites.

How serious the threat is

  • The CVE numbers leaked publicly on 20 October, so PHP released the fixes a day earlier than planned.
  • Cloudflare reports seeing early attacks, and watchTowr and Patchstack report exploitation attempts against both vulnerabilities.
  • Palo Alto Networks counts over 22 million publicly reachable PHP installations that are potentially affected.
  • Programs presented as ready-made exploits are circulating online. The PHP team had not found a working one among them when the fixes were released. Some may contain malware, so do not run them.

What to do now

1. Find out which PHP version the site uses

The php -v command shows the command-line version, which often differs from the version serving the site. Check the site's own version:

  • in WordPress: Tools → Site Health → Info → Server;
  • in the hosting control panel: "Select PHP Version" or "MultiPHP Manager" in cPanel, or the equivalent section in Plesk or DirectAdmin;
  • on your own server: a temporary file containing <?php phpinfo(); in the site directory, deleted immediately after the check.

With Debian, Ubuntu, Red Hat and AlmaLinux packages the version number does not change, because the distribution adds the fix to the same version. Check the distribution's security tracker to see whether the package already contains the fix for CVE-2026-109618 and CVE-2026-109619.

2. Update

  • Shared hosting: ask your provider whether PHP has been updated, and switch the site to 8.3 or 8.4 if it runs an older version. Before switching, check that the theme and plugins support the new version.
  • Your own server or VPS: install the updated packages and restart all PHP processes (systemctl restart php8.3-fpm or systemctl restart apache2). The fix does not take effect while old workers are still running.
  • Containers: rebuild the images with the fixed version and redeploy them. Also check base images that do not update automatically.
  • PHP 8.1 and older: plan an immediate move to 8.3 or 8.4. If that requires code changes, apply the temporary measures below and restrict access to the site until the migration is complete.

3. Temporary measures if you cannot update immediately

The PHP team warns explicitly that these settings reduce the risk but do not make an installation safe. Set them in php.ini, in the FPM pool configuration (php_admin_value) or in the Apache configuration, not through ini_set() or .user.ini, and restart every worker:

; CVE-2026-109619: disables file upload progress tracking
session.upload_progress.enabled = 0

; PHP 8.5 only
fatal_error_backtraces = 0

; CVE-2026-109618: no per-request memory limit
memory_limit = -1

; 8M if the site does not accept files, 32M if it does
post_max_size = 8M

memory_limit = -1 removes the per-request memory limit, so cap the memory of the whole service at the operating system level, for example with MemoryMax= in systemd or a container limit. Do not use ulimit -v or ulimit -d (RLIMIT_AS and RLIMIT_DATA), because they trigger exactly the vulnerable behaviour.

If the site does not accept multipart/form-data uploads and forms, block such requests at the web server or firewall. Cloudflare has added rules against the known attack variants on all plans, including the free one. They protect only traffic that passes through Cloudflare and do not replace updating.

How to check whether the server has been attacked

The attack happens below the application layer, so WordPress and other application logs usually do not show it. Review the server logs from 20 October onwards for:

  • Allowed memory size of … bytes exhausted messages, especially with in Unknown on line 0, meaning before the site's code started running;
  • crashed processes: exit signal Segmentation fault (11) in the Apache log or exited on signal 11 (SIGSEGV) in the PHP-FPM log;
  • series of unusual multipart/form-data POST requests to arbitrary URLs, followed by 500 responses;
  • unusually long or garbled PHPSESSID cookies in responses.

The absence of these entries does not prove there was no attack. If there are signs of one, also look for its consequences:

  • new or modified PHP files, especially in upload directories (find /var/www -name '*.php' -newermt 2026-10-20);
  • new cron jobs for the user the web server runs as;
  • new administrator accounts on the site;
  • outgoing connections from the server to unknown addresses.

Code run through the vulnerability has the web server's privileges and can read configuration files. If an attack is suspected, change the database password, API keys, SMTP credentials and payment service keys stored in wp-config.php, .env and similar files. Cleaning up a WordPress site after a compromise is covered in a separate article.

If the attacker had access to personal data of customers or employees, this is a personal data breach. In most cases it has to be reported to the data protection authority within 72 hours of becoming aware of it. Companies within the scope of the Bulgarian Cybersecurity Act also send an early warning to the sectoral incident response team within 24 hours.

VulnerabilitiesWebsites