PHP2Shell: update to the patched PHP version now

The patch for PHP2Shell has been released. As of Wednesday, October 21, 2026, at 4:00 PM Dutch time, PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35 are available. They address two critical vulnerabilities that allow an attacker to execute code on your server without logging in. The PHP team is clear: only updating makes you secure, and it must be done now.

The details were already public for a day, and security firm Sansec expected massive attacks within fifteen minutes of the release. Every hour a server remains unpatched counts.

In this article, you will read exactly what is vulnerable, which version you need, how to update safely, what to do if updating today is not possible, and how to check if someone has already gained access.

Updated on October 21, 2026, following the official release of PHP.

What is PHP2Shell?

PHP2Shell is the nickname for two vulnerabilities in PHP itself, both with a score of 9.2 out of 10 (CVSS v4.0). The name comes from an exploit tool that appeared in a leaked screenshot. PHP has now confirmed the situation:

CVEWhat goes wrong
CVE-2026-109618 — RCE via memory exhaustionIf PHP runs out of memory while building a request, it can be interrupted midway. During cleanup, PHP then treats that partially filled data as valid.
CVE-2026-109619 — RCE via residual stateInternal request data persists after the memory has already been released. A subsequent request in the same worker can use that data before it is properly reset.

Who is at risk?

According to PHP: every PHP installation that handles web requests. This applies to PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP, and LiteSpeed. The risk is greatest with mod_php: it has been demonstrated that a single request without login starts the attack before even one line of application code runs.

The vulnerability is therefore in PHP, not in WordPress, Laravel, WooCommerce, or a plugin. Updating your CMS will not solve this, and a site without an upload form is just as vulnerable.

Which version do you need?

Your PHP versionUpdate toNote
8.58.5.12Official release from php.net
8.48.4.27Official release from php.net
8.38.3.36Official release from php.net
8.28.2.35Official release; 8.2 is end-of-life on December 31, 2026, plan your upgrade now
8.1, 8.0, 7.4 and olderUpgrade to 8.2 or higherNo release from php.net. Some distributions and LTS vendors provide a backport; PHP has also published minimal source patches for 7.4, 8.0, and 8.1 for those who compile themselves

If you use packages from a Linux distribution, you do not need to look at this version number. Distributions received the fixes in advance and often apply them to their own version (backport). You can read how to check that below.

Note if you obtain PHP from the voluntarily maintained Remi repository (rpms.remirepo.net): it will not receive updates today. PHP recommends switching to distribution packages or compiling yourself.

Step 1: Identify what needs to be patched

First, update your servers that are accessible from the internet, starting with mod_php servers. Before you begin, save a copy of your web server and PHP logs from October 20: you will need them in step 3, and a deployment or log rotation could erase them.

Know what you need to patch

Do not forget staging environments, old campaign sites, management tools like phpMyAdmin, and containers. On a Debian or Ubuntu server:

# Welke PHP-versies zijn geïnstalleerd?
ls /etc/php

# Welke PHP-processen draaien er (FPM, Apache mod_php, LiteSpeed)?
ps -eo pid,comm,args | grep -E '[p]hp-fpm|[a]pache2|[h]ttpd|[l]sphp'

# Welke sites geven verzoeken door aan PHP?
sudo nginx -T | grep -E 'server_name|fastcgi_pass'

php -v on the command line says nothing about the version serving your website: FPM pools and Apache can load a different PHP. Never put a public phpinfo() page online to check this.

Step 2: How to update PHP on Linux

How you update PHP depends on where your PHP comes from. Check that first, as that is also where your fix will come from:

SourceIdentifiable byWhere the fix comes from
Debian or Ubuntu packagesapt-cache policy shows deb.debian.org, security.debian.org or security.ubuntu.comSecurity repository of your distribution (backport)
PPA / repo by Ondřej Surýapt-cache policy shows ppa.launchpadcontent.net/ondrej or packages.sury.orgNew upstream version in the PPA
RHEL, AlmaLinux, Rockydnf info php-fpm shows appstreamRed Hat / Alma / Rocky (backport)
Remi repositoryPackage names like php83-php-fpm or repo remi-*No update today
AlpinePackage names like php83-fpmAlpine repository
Control panel (cPanel, DirectAdmin, Plesk)PHP under /opt/cpanel/, /usr/local/php* or /opt/plesk/php/Update mechanism of the panel

Before you begin, create a snapshot or backup of the server. A security update is usually trouble-free, but if you are far behind, you will also pull in other changes.

Debian and Ubuntu

# 1. Pakketlijsten verversen
sudo apt update

# 2. Staat er een PHP-pakket op 'hold'? Dan wordt het stilletjes overgeslagen.
apt-mark showhold
# eventueel: sudo apt-mark unhold php8.3-fpm

# 3. Welke versie staat er en welke is beschikbaar? (doe dit per PHP-versie)
apt-cache policy php8.3-fpm

# 4. Alleen PHP bijwerken
sudo apt install --only-upgrade 'php8.3*'

# of gewoon alles bijwerken
sudo apt upgrade

Repeat steps 3 and 4 for every version in /etc/php, not just for the version the php command points to.

Are you using the distribution packages? Then the upstream version number often does not change: Debian and Ubuntu apply the fix to their own version. The package number and the changelog tell you if the fix is included:

dpkg -l | grep php8.3-fpm
zcat /usr/share/doc/php8.3-fpm/changelog.Debian.gz | grep -m3 -E 'CVE-2026-10961[89]'

If you do not get a match, the fix has not arrived yet. In that case, check the security advisory of your distribution (Debian, Ubuntu) and maintain emergency measures until the package is available.

Are you using Ondřej Surý’s PPA? Then apt-cache policy should show the new upstream version after the update, for example 8.3.36. The PPA only builds for supported Ubuntu versions (22.04 and 24.04). If you are still running on Ubuntu 20.04 or older, nothing more will come through this route: plan a migration to a new server.

RHEL, AlmaLinux, and Rocky Linux

# 1. Welke PHP-pakketten en welke bron?
dnf list installed 'php*'
dnf module list php        # welke PHP-stream staat aan (bijv. 8.2)?

# 2. Zijn er updates?
sudo dnf check-update 'php*'

# 3. Bijwerken
sudo dnf upgrade 'php*'

# 4. Zit de fix erin?
rpm -q --changelog php-fpm | grep -m3 -E 'CVE-2026-10961[89]'

Red Hat, AlmaLinux, and Rocky also backport: the version number remains the same, while the package number (the release) increases. The changelog is leading. If the fix is not yet included, follow the security notifications of your distribution and maintain emergency measures.

Are you using the Remi repository? PHP warns that rpms.remirepo.net has no updates today. You can then:

  • implement the emergency measures and monitor the Remi updates (sudo dnf check-update --enablerepo='remi*');
  • switch to your distribution’s PHP stream (dnf module reset php and dnf module enable php:8.2), provided your application works with that version;
  • or compile PHP yourself (see below).

Alpine Linux

sudo apk update
sudo apk upgrade 'php83*'      # vervang 83 door jouw versie
php83 -v

Control Panels

On servers with a control panel, PHP comes from the panel, not from your distribution. Update it via the panel:

  • cPanel/WHM (EasyApache): sudo dnf upgrade 'ea-php*' (on older systems yum), or via WHM → EasyApache. Update every ea-phpXX that is installed.
  • DirectAdmin (CustomBuild): da build update and then da build php.
  • Plesk: update the PHP components via Tools & Settings → Updates.

Afterwards, check per domain which PHP version is active and whether it is the patched build. Those on shared hosting cannot do this themselves: ask your host for confirmation.

Compiling yourself

If no package is available, for example with Remi or a custom installation, you can build PHP from source. Only do this if you know how your current PHP was built:

# Hoe is de huidige PHP gecompileerd?
php -i | grep 'Configure Command'

# Broncode van php.net halen (pas de versie aan)
wget https://www.php.net/distributions/php-8.3.36.tar.gz
tar xzf php-8.3.36.tar.gz && cd php-8.3.36

# Met dezelfde opties bouwen en installeren
./configure <opties van hierboven>
make -j"$(nproc)"
sudo make install

Verify the download with the signatures on the php.net download page. For PHP 7.4, 8.0, and 8.1, the PHP team has published separate source patches; these are linked in the security advisory.

Check which PHP your website is actually running

After the update and restart (see below), you want to be sure your site is running on the patched build, not just the command line.

# Versie van de geïnstalleerde FPM-binary
php-fpm8.3 -v

# Is de service ná de update gestart? Kijk naar 'Active: … since'
systemctl status php8.3-fpm

If you want to see it from the web server itself, temporarily place a file with a random name in the web root, open it once in your browser, and delete it immediately:

<?php echo PHP_VERSION, ' ', PHP_SAPI;

For an upstream version, you will see 8.5.12, 8.4.27, 8.3.36, or 8.2.35 here. For distribution packages with a backport, the old version number may remain; in that case, the changelog command above is your proof.

Restarting, and then really everything

CVE-2026-109619 concerns data that remains in a worker. An update without a restart therefore does nothing.

  • Restart PHP-FPM for each version, for example sudo systemctl restart php8.3-fpm, or Apache if PHP runs as a module.
  • Restart long-running PHP processes: queue workers, Laravel Horizon, schedulers, Reverb, Octane.
  • Search for processes still running on the old PHP binary:
ls -l /proc/*/exe 2>/dev/null | grep -i 'php.*deleted'

Docker, FrankenPHP, and hosting

  • Docker: an updated host does not repair the PHP in your containers. Pull the patched base image, rebuild, and deploy. Check with docker run --rm jouw-image php -v.
  • FrankenPHP: PHP is included in the binary itself, so you need a new FrankenPHP build.
  • Shared or managed hosting, cPanel, Plesk, DirectAdmin: ask your host to confirm that your domain is running on a patched build. Switching to a different PHP version in the panel says nothing about that.
  • PHP 8.1 or older: ask your distribution or LTS vendor for a backport, or upgrade. Until then: use the measures below, or take the site offline.

Is updating not possible today?

PHP lists a number of measures that reduce the known attack routes. They explicitly do not make your installation secure; see them as a bridge for hours, not weeks. Set them in php.ini, the FPM pool (php_admin_value / php_admin_flag), or the Apache configuration, not via ini_set() or a .user.ini, and then restart all workers.

Against CVE-2026-109619 (residual state)

; in php.ini, of per FPM-pool:
; php_admin_flag[session.upload_progress.enabled] = off
session.upload_progress.enabled = 0

; alleen op PHP 8.5:
fatal_error_backtraces = 0

Additionally, PHP advises:

  • Remove invalid or outdated PHP settings that generate a notification per request. Hiding notifications with error_reporting, display_errors, or @ does not help.
  • Resolve fatal errors and timeouts that an attacker can trigger, for example in upload, import, or cleanup code.

Against CVE-2026-109618 (memory exhaustion)

  • Set memory_limit = -1 via php_admin_value and ensure that no pool, folder, or application sets a limit again. Then handle memory usage with a container or cgroup limit that only stops the affected worker. Do not use RLIMIT_AS or RLIMIT_DATA for this: they can actually cause the vulnerable error.
  • Lower post_max_size: 8M if you do not need uploads, 32M if you do. Keep upload_max_filesize below that.
  • At the web server or proxy level, also limit the size of requests, the number of fields, multipart parts, and headers, even for requests without a valid Content-Length.
; per FPM-pool, bijvoorbeeld /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 6M
php_admin_flag[session.upload_progress.enabled] = off

Extra layer: blocking multipart requests

This is not official PHP advice, but it is a measure that many administrators already implemented yesterday. Those who do not need uploads can refuse multipart requests before they reach PHP. Do it in every server block or virtual host that forwards to PHP, including the catch-all.

Nginx (in the http context, plus the if at the top of each server block):

map $http_content_type $block_multipart {
    default       0;
    "~*multipart" 1;
}

# in elke server block:
if ($block_multipart) { return 403; }

Apache 2.4 (virtual host or at the top of .htaccess):

<If "req('Content-Type') =~ /multipart/i">
    Require all denied
</If>

As long as this is in place, file uploads, forms with attachments, and some form plugins (such as Contact Form 7) will not work.

Reduce your attack surface

  • Take staging sites and PHP applications that you do not immediately need offline until they are patched. CERT-EU advises isolating vulnerable internet-facing applications if necessary.
  • Restrict management tools such as phpMyAdmin to your own IP address.
  • Ensure your server is not accessible bypassing your CDN or WAF.

Shared hosting? You usually cannot reliably set these settings yourself there. Ask your host when your domain will be running on a patched PHP.

What does NOT help

  • Updating WordPress, Laravel, or plugins. The leak is in PHP, not in your application.
  • Security plugins such as Wordfence. These only run after PHP has already processed the request.
  • Settings via ini_set() or an FPM .user.ini. These come too late; PHP explicitly mentions this.
  • Hiding error messages with error_reporting, display_errors, or @.
  • RLIMIT_AS or RLIMIT_DATA as a memory limit. These can actually trigger the vulnerable error.
  • Only a WAF or CDN. This only helps if your server is not directly accessible via its IP address.
  • Updating without restarting workers. Running processes use the old PHP until a restart.

Step 3: Check if someone has already gained access

  • Search your web server and PHP logs for unusual multipart requests and PHP-FPM worker crashes.
  • Search for new or modified files in web roots, upload folders, plugins, and mu-plugins: find /var/www -type f -newermt '2026-10-20 15:00 UTC' (expect some noise from caches and logs).
  • Check .user.ini files and the auto_prepend_file setting for changes.
  • Review cron jobs, systemd units, and Supervisor for new tasks, and check for new SSH keys.
  • Watch for PHP processes starting a shell, Python, or curl/wget, and for unexpected outgoing connections from the PHP user.
  • Check your applications for any new administrator accounts.

Do you find anything? Isolate the server and preserve the logs. If the evidence points to a breach, rebuild the server and change every secret the PHP user had access to: .env files, database passwords, API keys, and app keys. A clean check is no guarantee, but it is a good sign.

After the update: cleaning up temporary measures

Is the patched PHP demonstrably running on all your sites and have all workers been restarted? Then roll back the emergency measures:

  • Set memory_limit back to a normal value. Without a limit, a single runaway script can cause the entire server to crash.
  • Set post_max_size and upload_max_filesize back if your sites need larger uploads.
  • Remove any multipart blockade on your web server and in your CDN, and then test a file upload and your most important forms.

session.upload_progress.enabled may remain off, unless your application uses that function.

Need help?

Customers with server management do not need to do anything: we have already implemented the temporary measures and will patch as soon as the update is available.

If you do not have a management contract, or if you are not sure if your server is properly shielded, contact Servermeister via [email protected] or 020 895 0045. We will take a look with you today.

Block "serverbeheer-aanbod-content" not found