Is Your Website Vulnerable to PHP2Shell? 6 Ways to Check (With Code Examples)
A practical guide with copy-paste scripts to check whether your PHP website is exposed to CVE-2026-109618 and CVE-2026-109619, including distro backports, Docker containers and signs of compromise.
PHP released emergency fixes on October 21, 2026 for two critical remote code execution flaws, CVE-2026-109618 and CVE-2026-109619, now widely known as PHP2Shell. The fixed releases are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Everything older is affected unless someone has backported the patch for you. This guide shows you, step by step and with copy-paste code, how to find out whether your website is actually exposed.
Why a Quick Version Check Is Not Enough
- Your website and your terminal may run different PHP versions. The
phpcommand on the shell is often a different build from the one serving web traffic through PHP-FPM or Apache. - Linux distributions backport fixes. Ubuntu, Debian, RHEL and others frequently patch PHP without bumping the upstream version number, so a version such as 8.3.6 can be safe while 8.3.35 from another source is not.
- Old workers keep running old code. If packages were updated but PHP-FPM or Apache was never restarted, the vulnerable code is still in memory.
- One server, many versions. Hosting panels often run several PHP versions side by side, and each site can use a different one.
Method 1: Run a Web-Based Check Script (Most Accurate for Your Site)
The script below runs inside the same PHP that serves your website, so it reports the version your visitors actually hit. It compares it against the official fixed releases, flags the risky mod_php setup, and shows the settings PHP recommends changing as a temporary mitigation. It is protected by a secret token so strangers cannot read it.
<?php
// php2shell-check.php - upload, open once, then DELETE this file.
// Open as: https://yoursite.com/php2shell-check.php?t=YOUR-SECRET
$secret = 'CHANGE-ME-TO-A-LONG-RANDOM-STRING';
if (!isset($_GET['t']) || !hash_equals($secret, (string) $_GET['t'])) {
http_response_code(404);
exit;
}
header('Content-Type: text/plain; charset=utf-8');
$fixed = ['8.2' => '8.2.35', '8.3' => '8.3.36', '8.4' => '8.4.27', '8.5' => '8.5.12'];
$branch = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
echo 'PHP version : ' . PHP_VERSION . PHP_EOL;
echo 'Server API : ' . PHP_SAPI . PHP_EOL . PHP_EOL;
if (version_compare($branch, '8.5', '>')) {
echo 'STATUS: Newer branch than 8.5 - check php.net for its status.' . PHP_EOL;
} elseif (!isset($fixed[$branch])) {
echo 'STATUS: UNSUPPORTED BRANCH (' . $branch . '). No official fix from PHP.' . PHP_EOL;
echo ' Upgrade, or confirm a vendor backport in your package changelog.' . PHP_EOL;
} elseif (version_compare(PHP_VERSION, $fixed[$branch], '>=')) {
echo 'STATUS: OK - official fixed release (' . $fixed[$branch] . ') or newer.' . PHP_EOL;
} else {
echo 'STATUS: VULNERABLE BY VERSION NUMBER - fixed in ' . $fixed[$branch] . PHP_EOL;
echo ' If your distro backported the fix, confirm it in the package changelog.' . PHP_EOL;
}
if (PHP_SAPI === 'apache2handler') {
echo PHP_EOL . 'WARNING: Apache mod_php detected - this is the highest-risk setup.' . PHP_EOL;
}
echo PHP_EOL . '--- Settings related to the official mitigations ---' . PHP_EOL;
echo 'session.upload_progress.enabled : ' . (ini_get('session.upload_progress.enabled') ? 'ON (mitigation not applied)' : 'OFF') . PHP_EOL;
echo 'memory_limit : ' . ini_get('memory_limit') . PHP_EOL;
echo 'post_max_size : ' . ini_get('post_max_size') . PHP_EOL;
echo 'upload_max_filesize : ' . ini_get('upload_max_filesize') . PHP_EOL;
if (PHP_VERSION_ID >= 80500) {
echo 'fatal_error_backtraces : ' . (ini_get('fatal_error_backtraces') ? 'ON (mitigation not applied)' : 'OFF') . PHP_EOL;
}How to use it
- Change the
$secretvalue to a long random string. - Upload the file to your website root (for example
public_html). - Open
https://yoursite.com/php2shell-check.php?t=YOUR-SECRETin your browser. - Read the STATUS line, then delete the file immediately. Never leave diagnostic scripts on a live server.
How to read the result
- STATUS: OK means you are on an official fixed release or newer. Still make sure all workers were restarted after the update.
- VULNERABLE BY VERSION NUMBER means the upstream version is older than the fix. If PHP came from your Linux distribution, use Method 3 to confirm whether a backport is already in place.
- UNSUPPORTED BRANCH means you are on PHP 8.1 or older. You need a vendor backport or an upgrade.
- WARNING: Apache mod_php means the attack can trigger before your application code runs. Treat this as urgent.
Method 2: Check From the Command Line (VPS or Dedicated Server)
# Version used by the command line (may differ from your website!)
php -v
# List every PHP-FPM / Apache process and when it was started
ps -eo pid,lstart,cmd | grep -E 'php-fpm|php[0-9.]*-fpm|apache2|httpd' | grep -v grep
# Which PHP versions are installed side by side? (Debian/Ubuntu)
ls /etc/php/Compare the process start times with the time your PHP packages were updated. A worker that started before the update is still running the old, vulnerable code and needs a restart.
Method 3: Confirm Distribution Backports in the Package Changelog
If your PHP comes from your operating system or a well-known package source, the changelog is the most reliable proof that the fix is in place.
# Debian / Ubuntu: search the package changelog for the CVE IDs
# (replace 8.3 with your branch: 7.4, 8.1, 8.2, 8.4 ...)
zgrep -E 'CVE-2026-10961(8|9)' /usr/share/doc/php8.3-common/changelog.Debian.gz
# Installed package version and source repository
apt-cache policy php8.3-common# RHEL / AlmaLinux / Rocky / Fedora
rpm -q php-common
rpm -q --changelog php-common | grep -E 'CVE-2026-10961(8|9)'If the grep returns lines mentioning CVE-2026-109618 and CVE-2026-109619, your package includes the fix. If it returns nothing, either the fix is not installed yet or your package source writes changelogs differently, in which case check its official security notice.
Method 4: WordPress Site Health
In the WordPress dashboard, open Tools, Site Health, Info and expand the Server section to see the PHP version. Remember that WordPress itself needs no update for PHP2Shell, because the flaw is in PHP, not in WordPress. If you are on shared or managed hosting, ask your host directly whether the October 21 PHP security release has been applied to your server.
Method 5: Check Docker Containers
# Check the PHP version inside every running container
for c in $(docker ps -q); do
echo -n "$(docker inspect -f '{{.Name}}' $c): "
docker exec $c php -r 'echo PHP_VERSION, " ", PHP_SAPI, PHP_EOL;' 2>/dev/null || echo 'no php'
doneContainers built from an old image stay vulnerable until you rebuild them on a patched base image and redeploy.
Method 6: Look for Signs That Something Already Happened
Attack attempts were reported before the patch was public, so if your server was exposed it is worth a quick look. These checks are not proof either way, but they can point you to problems.
# Look for worker crashes around and before the patch date
sudo grep -iE 'SIGSEGV|segmentation fault|exited on signal 11' /var/log/php*-fpm.log /var/log/apache2/error.log 2>/dev/null | tail -n 50
# Recently modified PHP files in your web root (last 3 days)
find /var/www -name '*.php' -mtime -3 -type f -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort- A burst of segmentation faults in PHP-FPM or Apache logs around October 20 to 22 deserves a closer look.
- Unknown PHP files, especially in upload or cache folders, can be web shells.
- Unexpected new admin users, cron jobs or outgoing connections are red flags.
- If you find anything suspicious, treat the server as compromised: isolate it, rotate credentials and restore from a clean backup after patching.
Quick Decision Table
- 8.5.12, 8.4.27, 8.3.36, 8.2.35 or newer, workers restarted: patched.
- Older 8.2 to 8.5 build from your distro with the CVEs in the changelog: patched.
- Older 8.2 to 8.5 build with no backport: vulnerable, update now.
- PHP 8.1 or older: vulnerable unless your vendor shipped a backport. Plan an upgrade.
- Not sure: assume vulnerable and ask your host.
Official References
Admin PenduCoder
Full-stack developer and educator. Writes about Laravel, Next.js, applied AI and the unglamorous parts of shipping software.
Get in touch →