Critical PHP vulnerability (PHP2Shell): what it is and how to fix it on Ubuntu with Apache or Nginx

Equipe HcodeOctober 21, 202610 min read

In this article

On October 21, 2026, the PHP project released versions 8.5.12, 8.4.27, 8.3.36, and 8.2.35. They fix two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619. Both received a score of 9.2 on CVSS v4.0 and allow for remote code execution, meaning an attacker can run commands on the server. Researchers dubbed the pair of vulnerabilities PHP2Shell. If you maintain any server running PHP, the fix is simple: update PHP and restart the services that use it. In this article, you will understand what the vulnerabilities are, who is affected, and see a complete step-by-step guide for an Ubuntu server with Apache or Nginx.

What happened

On October 20, the PHP security team issued an early warning: there would be an emergency release the next day at 14:00 UTC (11:00 AM Brasília time) to address two critical vulnerabilities. The team also stated that they might expedite the release if details leaked or signs of exploitation appeared. On the same day, CERT-EU published an alert, and the UK's National Cyber Security Centre also warned about the issue.

On the 21st, the fixed versions were released, and Linux distributions, which had received the fixes ahead of time, published updated packages. Ubuntu, for example, issued the security notice USN-8948-1.

The two vulnerabilities, in simple terms

CVE-2026-109618: memory corruption when memory is exhausted

When a request causes PHP to hit the memory limit, processing can be interrupted while the internal data of the request is still half complete. Later, during the cleanup of the request, PHP treats this incomplete data as valid. An attacker can deliberately provoke this situation with a crafted request. According to the PHP team, remote code execution was confirmed via HTTP on servers running Apache and mod_php. From code analysis, PHP-FPM is also vulnerable, but no complete exploitation via FPM had been demonstrated at the time of release.

CVE-2026-109619: stale state reused between requests

Servers reuse the same process (the worker) to handle multiple requests. Due to this flaw, internal information from a request can continue to exist after its memory has been freed, and the subsequent request on the same worker may use this stale data. It is a case of use-after-free. The confirmed paths involve session handling and fatal error backtraces. Besides executing code, the flaw could leak data from the server's memory.

Who is affected

  • Any PHP installation that handles web requests: PHP-FPM (common with Nginx), Apache with mod_php, php-cgi, FrankenPHP, and LiteSpeed. The PHP team considers Apache with mod_php the highest-risk case.
  • Older versions as well. According to Laravel Forge, the vulnerabilities exist in PHP versions since 2004.
  • Any application. The attack occurs before the application code runs. Researchers claim to have achieved code execution without login against WordPress, Drupal, and Joomla, and even against a simple "Hello World".

Regarding exploitation: the PHP team stated that they had not identified functional exploits by the time of release. CERT-EU reported that proof of concepts began circulating, and Cloudflare stated that it had seen attack traffic against its clients. Therefore, treat the update as urgent.

Fixed versions

PHP BranchFixed VersionBranch Status
8.58.5.12Active support
8.48.4.27Active support
8.38.3.36Security fixes only, until 12/31/2027
8.28.2.35Security fixes only, until 12/31/2026
8.1 or earlierNo official PHP fixEnd of life

Attention: on Ubuntu, the version number may be different

This is the point that confuses the most. The official Ubuntu packages do not change the version of PHP: they apply the fix to the version that the distribution is already using (the so-called backport). Therefore, a corrected Ubuntu 24.04 continues to show PHP 8.3.6 in php -v, not 8.3.36. What changes is the package revision. These are the fixed versions according to USN-8948-1:

UbuntuPackageFixed Package Version
26.10php8.58.5.9-0ubuntu2.1
26.04 LTSphp8.58.5.4-0ubuntu1.5
24.04 LTSphp8.38.3.6-0ubuntu0.24.04.13
22.04 LTSphp8.18.1.2-1ubuntu2.28

Note that Ubuntu 22.04 fixed PHP 8.1, even though this branch is no longer receiving fixes from the PHP project. Ubuntu 20.04 and earlier versions also received a fix, but only through ESM, which requires Ubuntu Pro (free for up to 5 machines).

If you installed PHP from Ondřej Surý’s repository (the ondrej/php PPA, commonly used for newer versions), then the version follows that of PHP, such as 8.4.27. And a warning: Ubuntu's automatic updates (unattended-upgrades) only apply what comes from the official Ubuntu security repository. Those using the PPA need to update manually.

Step-by-step: how to fix on Ubuntu with Apache or Nginx

The commands below use PHP 8.3 as an example. Replace 8.3 with the version of your server. Run everything with a user that has sudo.

1. Discover which PHP versions are installed

php -v
ls /etc/php
dpkg -l 'php*' 'libapache2-mod-php*' | awk '/^ii/ {print $2, $3}'

The last command lists each PHP package with the installed version. Note the result for later comparison. If more than one version appears in /etc/php, update all, including those that no site uses today.

2. Discover how PHP is executed

This defines which service you will restart at the end.

Apache:

apache2ctl -M 2>/dev/null | grep -E 'php|proxy_fcgi'
ls /etc/apache2/conf-enabled | grep -i fpm
  • If php_module (or php8.3_module) appears, Apache uses mod_php.
  • If proxy_fcgi_module and a file like php8.3-fpm.conf appear, Apache uses PHP-FPM.

Nginx: Nginx always uses PHP-FPM. See which version each site calls:

grep -R "fastcgi_pass" /etc/nginx/sites-enabled/ /etc/nginx/conf.d/ 2>/dev/null

A line like fastcgi_pass unix:/run/php/php8.3-fpm.sock; indicates that the site uses PHP-FPM 8.3.

3. Discover where the package comes from

sudo apt update
apt-cache policy php8.3-cli
ls /etc/apt/sources.list.d/

In the output of apt-cache policy, check the line Candidate and the source. If it comes from ppa.launchpadcontent.net/ondrej/php or packages.sury.org, PHP comes from Ondřej's repository, and the candidate version should be that of the PHP project (for instance, 8.3.36). If it comes from security.ubuntu.com or archive.ubuntu.com, compare with the table above for Ubuntu. If the candidate version is still not the fixed one, the package has not reached the repository yet: wait a little and run sudo apt update again.

4. Make a backup

Before making changes in production, back up the site files, database, and PHP configurations. A simple example:

sudo tar czf /root/backup-php-config-$(date +%F).tar.gz /etc/php /etc/apache2 /etc/nginx 2>/dev/null

If the server is a VM in the cloud, taking a snapshot of the disk is even better. And if you have a staging environment, apply the update there first.

5. Update PHP packages

This command updates all already installed PHP packages without installing anything new. The --force-confold option keeps your php.ini and FPM configurations:

sudo apt-get install --only-upgrade -y \
  -o Dpkg::Options::="--force-confold" \
  $(dpkg -l 'php*' 'libapache2-mod-php*' | awk '/^ii/ {print $2}')

If you prefer, sudo apt update && sudo apt upgrade updates the entire system, which is also recommended by Ubuntu.

6. Restart services

Updating the package is not enough: the process that was already running retains the old code in memory until it is restarted. Choose your case:

Apache with mod_php:

sudo systemctl restart apache2

Apache or Nginx with PHP-FPM (repeat for each installed version):

sudo systemctl restart php8.3-fpm

With PHP-FPM, there is no need to restart Apache or Nginx since they just forward requests to FPM. The restart will take the site down for a few seconds, so prefer a time with low access.

Long-running PHP processes: queues, Supervisor workers, Laravel Horizon, Octane, or any script that runs continuously from the command line will continue with the old version until they are restarted. In Laravel, for example:

php artisan queue:restart
php artisan horizon:terminate
sudo supervisorctl restart all

If you don't know everything that is running on the server, restarting the machine (sudo reboot) solves it at once.

7. Confirm that the fix is active

dpkg -l 'php*' 'libapache2-mod-php*' | awk '/^ii/ {print $2, $3}'
php -v
php-fpm8.3 -v
systemctl status php8.3-fpm --no-pager | head -5

Check if the versions match the corresponding table (from PHP, if you use the PPA; from Ubuntu, if you use the official packages) and if the service was started after the update. In the official Ubuntu packages, you can also look for the CVEs in the changelog:

apt changelog php8.3-fpm 2>/dev/null | grep -m2 -E 'CVE-2026-10961[89]'

Finally, open the site and check if everything works normally.

What if I'm still using PHP 8.1 or earlier?

The PHP project will not fix these branches. Your options are:

  • Ubuntu 22.04 with the official PHP 8.1: Ubuntu has already fixed it. Just follow the step-by-step guide.
  • Ubuntu 20.04 or earlier: activate Ubuntu Pro to receive the fix through ESM, and plan to migrate to a supported version.
  • Old PHP from another source: migrate to a supported version (8.3 or newer) as soon as possible. Test first, as older plugins and libraries may break in newer versions.

If you can't update right now

The PHP team is clear: there is no complete mitigation, only updating resolves. In the meantime, some measures reduce risk:

  • Disable upload progress session in php.ini or in the FPM pool with session.upload_progress.enabled = 0 and restart all workers. Doing this with ini_set() or .user.ini does not work.
  • Reduce the maximum request size: post_max_size to 8M if the site does not receive uploads, or 32M if it does, with upload_max_filesize smaller than that. On the web server, adjust client_max_body_size (Nginx) or LimitRequestBody (Apache) in the same manner.
  • In PHP 8.5, set fatal_error_backtraces = 0.
  • If the site passes through Cloudflare, it published WAF rules for known vectors, including on the free plan. This is a stopgap protection and only applies to traffic that passes through it.

CERT-EU also recommends, in the most critical cases, removing public access to the application until the fix.

It's worth checking if there was an intrusion

If the server was exposed with a vulnerable version, run a quick check after updating:

# Modified PHP files in the last 7 days
sudo find /var/www -name "*.php" -mtime -7 -not -path "*/cache/*"

# Last logins and scheduled tasks
last -n 20
sudo crontab -l; ls /etc/cron.d

Also check for new admin users in the application (in WordPress, under Users) and strange requests in the Apache or Nginx access logs. Up to the publication of this article, neither PHP nor security agencies had disclosed specific indicators of compromise.

And what about users of WordPress?

The flaw is in PHP, not in WordPress. Updating WordPress, plugins, or themes does not fix the problem. On shared or managed hosting, the provider updates PHP: confirm with them. On VPS or your own server, follow the step-by-step above. To see the PHP version from the panel, go to Tools, Site Health, Information tab, Server section.

Conclusion

The vulnerabilities CVE-2026-109618 and CVE-2026-109619 affect practically any server running PHP, and the only complete fix is to update. In summary: discover the version and source of the packages, back up, update, restart Apache or PHP-FPM and the workers, and confirm the version. If your server is still running PHP 8.1 or earlier, take advantage of the scare to plan the migration.

Want to deepen your knowledge in PHP and Linux servers? Check out the courses from the Hcode platform and follow the blog.

Frequently asked questions

My Ubuntu shows PHP 8.3.6. Am I vulnerable?

Not necessarily. In the official packages of Ubuntu 24.04, the fix arrives in the package revision 8.3.6-0ubuntu0.24.04.13. Check the complete version of the package with dpkg -l 'php8.3*', not just php -v.

Do I need to restart Nginx?

No. With Nginx, who executes PHP is PHP-FPM, so just restart the php8.x-fpm service. With Apache and mod_php, restart apache2.

Do Ubuntu's automatic updates resolve?

If you are using the official Ubuntu packages and unattended-upgrades is active, the fix is applied within 24 hours, but the services still need to be restarted. If you are using Ondřej's PPA, the automatic update does not cover PHP.

Changing php.ini settings resolves?

No. The settings reduce risk but the PHP team states that the only complete mitigation is to update.

Sources

Keep learning with Hcode

Sign up for the course platform and follow the next blog guides.