News
PHP CVE-2026-109618 and CVE-2026-109619: updating your server step by step
The Cybersecurity Centre warned about two PHP vulnerabilities. Which versions are fixed, how to check your server, and the traps we hit on real servers.
· 10 min read

In October 2026 the national cybersecurity centre published an advisory about two PHP vulnerabilities — CVE-2026-109618 and CVE-2026-109619. They affect PHP-based websites, information systems, control panels and other services. PHP-FPM, Apache mod_php and every other PHP environment need to be checked.
In this post we turn the advisory's recommendations into practical steps and show the traps we ran into ourselves while patching real servers. They look trivial, but they are exactly why a server that is "updated" keeps running an old, vulnerable PHP.
What is known and what is not
Fixed versions (or anything later in the same branch):
- PHP 8.2.35
- PHP 8.3.36
- PHP 8.4.27
- PHP 8.5.12
If PHP comes from distribution packages (Ubuntu, Debian, RHEL and others), the version number may look different: distributions backport the fix into an older version number. In that case, confirm the fix through the distribution vendor's security notice.
The technical details of the bugs are not public in our sources, so we will not speculate about how they work. The practical conclusion is simple: find every system running PHP, update it, and confirm that the update is actually running.
Updating the package is half the job. The other half is making sure the old processes are gone and the new binary is running.
Why it matters for the expertise
The official cybersecurity expertise also checks software versions. If a server runs a PHP version with a published vulnerability, it becomes a separate finding in the report. On top of that, many servers announce their PHP version themselves through the X-Powered-By: PHP/8.3.x header. That is recorded as information disclosure and lets the reviewer identify the version at a glance.
Updating PHP and hiding the version before submission is one of the cheapest and fastest findings to close.
Step 1: find every PHP installation
Start with an inventory, beginning with internet-facing systems: websites, portals, control panels. A single server often has several PHPs, and they are rarely all installed by the same package manager.
# Installed via the package manager
ls /usr/bin/php* /usr/sbin/php-fpm* 2>/dev/null
dpkg -l | grep -E '^ii\s+(php|lsphp)' | awk '{print $2, $3}'
rpm -qa | grep -Ei '^(php|lsphp)' # RHEL/Alma/Rocky
# PHP compiled by the panel itself (aaPanel-style panels)
ls -d /www/server/php/*/ 2>/dev/null
# OpenLiteSpeed lsphp
ls -d /usr/local/lsws/lsphp*/ 2>/dev/null
# PHP processes running right now
ps -eo pid,user,cmd | grep -E 'php-fpm|lsphp|apache2|httpd' | grep -v grep
For containers:
docker ps --format '{{.Names}} {{.Image}}'
docker exec <container> php -v
Put the results in a table: server, PHP source (apt, panel, LiteSpeed, container), version, which site uses it, whether it is reachable from the internet.
Step 2: find out which PHP is actually running
Here is the first trap. php -v only shows the CLI version — the first php binary on your PATH. The site is served by PHP-FPM, mod_php or lsphp, and those can be a completely different version.
The correct way is to look at the binary of the running master process:
pgrep -a php-fpm
# 1234 php-fpm: master process (/etc/php/8.3/fpm/php-fpm.conf)
ls -l /proc/1234/exe
# /proc/1234/exe -> /usr/sbin/php-fpm8.3
/usr/sbin/php-fpm8.3 -v
The same applies to a panel's PHP: ls -l /proc/<pid>/exe will point to something like /www/server/php/83/sbin/php-fpm, and that is the binary whose version you need to check.
If the output of ls -l /proc/<pid>/exe ends with (deleted), that is an important sign: the package was updated and the file on disk replaced, but the old binary is still running in memory. Until that process is restarted, the vulnerability is not closed.
Step 3: update each source
Distribution packages (apt, dnf)
# Debian/Ubuntu
apt update
apt install --only-upgrade 'php8.3*'
# Confirm the fix via the changelog
apt changelog php8.3-fpm 2>/dev/null | grep -E 'CVE-2026-10961[89]'
# RHEL and derivatives
dnf update 'php*'
rpm -q --changelog php-fpm | grep -E 'CVE-2026-10961[89]'
If PHP comes from a third-party repository, its version numbers usually match the official PHP releases and can be compared directly with the list above.
PHP compiled by a panel
aaPanel-style panels build PHP from source themselves and place it in folders like /www/server/php/83. apt upgrade does not touch that copy at all. A server owner can run the apt update, decide "everything is updated", while the site keeps running on the panel's PHP.
Such a PHP is updated through the panel's own software manager or rebuilt. Then check the binary version directly:
/www/server/php/83/bin/php -v
/www/server/php/83/sbin/php-fpm -v
OpenLiteSpeed and lsphp
OpenLiteSpeed ships its own lsphp packages (lsphp83, lsphp84 and so on). They are updated from the LiteSpeed repository and have nothing to do with the usual php8.3-* packages:
apt install --only-upgrade 'lsphp83*'
systemctl restart lsws
ps -eo pid,lstart,cmd | grep lsphp | grep -v grep
Use the last command to confirm that the lsphp processes started after the restart — no old process should be left behind.
Containers
Restarting a container is not enough: it comes back from the old image. Rebuild the image from an updated base image:
docker build --pull --no-cache -t myapp:latest .
docker compose up -d --force-recreate
docker exec <container> php -v
If the Dockerfile uses a floating tag like FROM php:8.3-fpm, --pull brings in the latest patch release. If the version is pinned (php:8.3.20-fpm), change the tag to a fixed version.
Unused versions
Another trap: a php8.1 or php8.5 CLI installed at some point for testing is still sitting on the server. No site uses it, but it is just as vulnerable, and the expertise scanners may find it. You have two options: update it or remove it. Before removing, make sure no cron jobs or scripts call it:
grep -rE 'php8\.1|php8\.5' /etc/cron* /var/spool/cron 2>/dev/null
apt purge 'php8.1*'
Step 4: restart and confirm
After updating the packages, PHP services and worker processes must be restarted:
systemctl restart php8.3-fpm # or the panel's service for its PHP
systemctl restart apache2 # if mod_php is used
systemctl restart supervisor # Laravel queues and other workers
Queue workers, long-running PHP scripts and daemons are separate processes and can also stay on the old binary. Then check:
for p in $(pgrep -f 'php'); do ls -l /proc/$p/exe; done | grep deleted
This command should print nothing. On Debian/Ubuntu the needrestart utility also lists services still running with old libraries.
Finally, hide the version header. In php.ini:
expose_php = Off
Behind nginx you can additionally add fastcgi_hide_header X-Powered-By;.
If you cannot update right away
Sometimes an immediate update is not possible: an old application does not run on the new version, or a change window is needed. In that case:
- Temporarily restrict external access to the system — for example, keep the admin panel reachable only from the internal network or via VPN.
- Apply the temporary mitigations recommended by the vendor.
- Turn on WAF filtering.
But be clear about this: WAF filters and temporary settings do not fully remove the vulnerability. They only buy time. Set a concrete update plan and deadline.
Analyse the logs
Alongside the update, check whether the vulnerability was exploited earlier. Look through web server, PHP and security logs for suspicious requests, unauthorised file changes and unexpected processes:
# Recently modified or created PHP files
find /var/www -name '*.php' -newermt '2026-10-01' -ls
# PHP files in folders like uploads
find /var/www -path '*uploads*' -name '*.php'
# Processes running as the web server user
ps -u www-data -o pid,lstart,cmd
# Outbound connections from PHP processes
ss -tnp | grep -E 'php|lsphp'
In the access log, watch for POST requests to unfamiliar .php files, unusually long parameters, and many error responses from one address in a short time.
If you find signs of an incident, first preserve the logs and evidence (make copies, delete nothing) and notify the Centre. We showed what cleaning a compromised site looks like in detail in our WordPress backdoor analysis.
Short checklist
- Every PHP installation on every server is inventoried: apt/dnf, panel, lsphp, containers.
- For each site, the PHP binary serving it is identified via
/proc/<pid>/exe. - Versions are 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 or later; for distribution packages, the fix is confirmed by the vendor notice.
- Unused PHP versions are updated or removed.
- PHP-FPM, Apache, lsws and workers are restarted; no
(deleted)binaries remain. - Containers are rebuilt from a new image.
expose_php = Off, noX-Powered-Byheader.- Systems that cannot be updated have external access temporarily restricted and an update deadline.
- Logs are analysed; suspicious files and processes are checked.
Summary
Closing these vulnerabilities is not technically hard, but on real servers PHP usually lives in several places, and if even one is missed, the server stays vulnerable. All four steps — inventory, update, restart and confirm — have to be done.
Want to know which PHP is really running on your server and whether anything else is left open? Request a security scan — the Claude AI agent and our specialist will review your server configuration, and we will help close the holes we find and prepare for the expertise.


