Find out in seconds whether your servers are vulnerable to, or already compromised through,
CVE-2026-109618 and CVE-2026-109619.
php2shell is a pair of critical bugs in PHP itself that let anyone run code on your server without logging in. They leaked on 20 October 2026 and fixes shipped on 21 October 2026. The scripts here are read-only.
Linux (run as root):
curl -fsSLO https://raw.githubusercontent.com/SPOTWHALE/php2shell-check/main/check-php2shell.sh
sudo bash check-php2shell.sh --huntWindows (XAMPP, WAMP, Laragon, IIS), from an elevated PowerShell:
powershell -ExecutionPolicy Bypass -File .\check-php2shell.ps1| Command | What it does |
|---|---|
sudo bash check-php2shell.sh |
Am I vulnerable? |
sudo bash check-php2shell.sh --hunt |
Am I vulnerable, and was I already hacked? |
sudo bash check-php2shell.sh --hunt --since 2026-06-01 |
Same, looking further back in time |
sudo bash check-php2shell.sh --summary |
One-line result, for many servers |
bash check-php2shell.sh --url https://example.com |
Weak remote check from the site's HTTP headers |
Exit code: 0 all clear, 1 vulnerable, 2 needs a manual look, 3 (--url only) version could not be read.
Note
--url only reads the version a site advertises in its Server / X-Powered-By headers, so you can triage a site you have no shell on. It is a weak hint: most servers hide the version (expose_php=Off → UNKNOWN, which does not mean safe), headers can be faked, and a distro backport keeps the old number. The on-server check above is the real answer.
Yes, if any PHP that serves web traffic (php-fpm, Apache mod_php, php-cgi, LiteSpeed, FrankenPHP, Docker) is older than:
| Branch | Fixed in |
|---|---|
| 8.5 | 8.5.12 |
| 8.4 | 8.4.27 |
| 8.3 | 8.3.36 |
| 8.2 | 8.2.35 |
| 8.1 and older | No fix. End-of-life: upgrade or take it off the internet |
Important
The bug is in the PHP runtime, not your code. composer audit, plugin scanners and code reviews will not find it. Only the PHP version matters.
Note
Debian, Ubuntu and RHEL often patch PHP without changing the version shown by php -v. The script checks the package changelog, so trust its result over the raw version number.
# Debian / Ubuntu
sudo apt update && sudo apt install --only-upgrade 'php*'
sudo systemctl restart 'php*-fpm' apache2
# RHEL / Alma / Rocky
sudo dnf upgrade 'php*'
sudo systemctl restart php-fpm httpdWarning
Restart php-fpm and Apache after upgrading. Until you do, they keep running the old, vulnerable binary.
Docker, control panels, and if you can't patch today
- Docker: pull the new
php:image tag, rebuild and redeploy. Old images stay vulnerable. - cPanel, Plesk, DirectAdmin: apply the panel's PHP updates. Plesk has an advisory.
- Can't patch today: set
session.upload_progress.enabled = Offin the php.ini of every SAPI and put the site behind a WAF (Cloudflare has rules, including on the free plan). This reduces exposure but is not a fix.
Run with --hunt. There are no official indicators of compromise yet, so it looks for what an attacker does after getting in: shells started by PHP, webshells, unknown processes and outbound connections, new cron jobs, users or SSH keys, and crash spikes in the logs. Everything it prints is a lead, not proof.
If it finds something:
- Don't delete it yet. Snapshot the disk and copy the logs first.
- Isolate the server, patch PHP, and restart php-fpm and Apache.
- Rotate every secret the web user could read: database passwords,
.envand API keys, SMTP, cloud keys,APP_KEY. Do this on any exposed vulnerable server, even if nothing turned up, because CVE-2026-109619 can leak memory. - If the attacker reached root, or you can't explain what you found, rebuild from a clean image.
Everything --hunt checks, and why
| What it looks for | Why it matters |
|---|---|
sh, bash, python, perl, curl, wget, nc started by php-fpm, php-cgi, Apache or lsphp |
PHP almost never needs a shell. Strongest live signal. |
| Processes running as the web user that are not PHP or web server workers | Backdoors, miners and reverse shells run as the web user. |
Webshell code in web roots at any age: eval($_POST[...]), eval(base64_decode(...)), system($_GET[...]) |
Attackers fake file dates, so contents are checked, not just timestamps. |
PHP files changed since the date, and PHP files in /tmp, /var/tmp, /dev/shm |
Files nobody deployed. |
Changed cron, /etc/passwd, /etc/shadow, sudoers, SSH keys, systemd units, /etc/ld.so.preload |
Ways to keep access after you patch. |
| Outbound connections from PHP, web server or shell processes | Reverse shells and data theft. |
Spikes of Allowed memory size ... exhausted, exited on signal 11, Segmentation fault |
Both bugs are memory bugs, and attack attempts crash workers. |
| Client IPs with many POST requests ending in HTTP 500 | Attack attempts and scanners. |
Manual checks the script can't do
- Compare the live web root with git or your last clean deploy:
git status,git diff, orrsync -rcn --delete clean/ live/. - WordPress:
wp core verify-checksumsandwp plugin verify-checksums --all, and look for unknown admin users. - Look for new admin accounts in your application's database.
- Check your WAF or Cloudflare dashboard for blocked attempts.
Check many servers at once
# hosts.txt: one host per line
while read -r h; do
ssh -n "$h" 'sudo bash -s -- --summary' < check-php2shell.sh
done < hosts.txt
# or with Ansible
ansible all -b -m script -a "check-php2shell.sh --summary"Output, one line per host:
web01 VULNERABLE vulnerable=2 review=0 patched=0
web02 OK vulnerable=0 review=0 patched=3
What the Linux script scans
- Every
php,php-fpm*,php-cgi*,lsphp*andfrankenphpbinary, including control panel installs (/opt/plesk/php,/opt/cpanel/ea-php*,/opt/remi,/usr/local/php*,/usr/local/lsws) - Apache
libphp*.soandmod_php*.somodules - Running Docker containers
- Whether PHP is serving web traffic right now
- Distro backports, via the package changelog
- Processes still running a replaced binary (need a restart)
- The interim
session.upload_progress.enabledsetting
Limits: it checks versions, it does not exploit anything. It cannot see stopped containers, images, other machines, or PHP compiled into unusual software. If a result looks wrong, check the official PHP advisory and your vendor's advisory.