PHP2Shell Check (CVE-2026-109618 · CVE-2026-109619)

A free, open-source tool that checks non-destructively whether the PHP sites you run are exposed to PHP2Shell.

Free · MITPython 3.8+ stdlib onlyNo attack trafficReports in English · 한국어 · 日本語

⚠️ Use only on systems you own or are authorized in writing to test. Even non-destructive scanning without permission may be illegal in your jurisdiction (LEGAL.md).

What is PHP2Shell

Two PHP runtime vulnerabilities disclosed on 2026-10-21, both rated CVSS v4.0 9.2. They lead to unauthenticated remote code execution (RCE), and virtually every PHP installation that serves web requests (Apache mod_php, PHP-FPM, …) is affected. Public PoCs exist, and real attack attempts were observed from 10-17, four days before disclosure.

PHP branchFixed in
8.58.5.12 or later
8.48.4.27 or later
8.38.3.36 or later
8.28.2.35 or later
8.1 and olderNo official fix release — use distro/LTS vendor packages or upgrade

Distribution packages (e.g. 8.2.7-1+deb12u5) may carry backported fixes despite a lower version number. Baseline as of 2026-10-23. Details: PHP vulnerability trends §2

Step 1 — Triage from your site's URL

Enter your site's address and this page builds a command to run on your own computer. The checker sends a single HTTP GET to the target and compares the PHP version exposed in the response headers against the fixed versions.

The address you enter never leaves this page. The command is built inside your browser, and this site uses no analytics scripts.

Reading the result

VerdictMeaning
likely_vulnerableThe exposed PHP version is below the fixed version, or is an EOL branch (below 8.2) with no official fix. Confirm with Step 2.
not_vulnerable_by_versionThe exposed version is at or above the fixed baseline. A supporting signal only, not a guarantee.
unknownPHP traces found but the version is hidden (or only partially shown, like 8.3).
not_detectedNo PHP traces in the response. This does not mean PHP is absent.
error / invalidConnection/TLS error, or malformed URL.

Production servers usually hide the version, so unknown is common. The version alone cannot tell whether an attack path actually holds; if you have server access, run Step 2.

Step 2 — Confirm on the server

Run this on the (Linux) server running PHP. It only reads configuration files, package data, /proc and logs — zero commands executed, zero network requests. It decides per-CVE reachability from the SAPI (mod_php/FPM) and effective settings (memory_limit, session.upload_progress.enabled, …) and reports which file and line to fix.

curl -fsSLO https://raw.githubusercontent.com/neoqmin/php2shell/v0.1.0/php2shell_host.py
echo '50a48c79c120774e9dccc27ee12672444b7730b31a32c2b833e650920ebf0925  php2shell_host.py' | sha256sum -c -
sudo python3 php2shell_host.py --lang en

Output goes to ./php2shell_report_<host>/ as report.json, report_en.md and report_en.html (A4 printable). The report contains the server's vulnerability details — do not publish it.

Sample report (local lab, no real target): HTML · Markdown · JSON

VerdictMeaning
ReachableThe attack path's preconditions hold given this server's SAPI and effective configuration
Mitigated (temporary)A temporary mitigation is applied before request parsing. Not safe — configuration alone does not fully mitigate
UndeterminedInsufficient evidence or failed to read config. This is not "unreachable"
PatchedAt or above the fixed version, or the package changelog records a backport of both CVEs

Supported: Debian/Ubuntu packages (Apache mod_php, nginx/Apache + PHP-FPM) and the official Docker php:*-apache image. RHEL-family package versions, the official php:*-fpm image, php-cgi, LiteSpeed and FrankenPHP are not assessed yet. See the README for all options and limitations.

If you cannot patch right now

Updating PHP is the only complete fix. Temporary mitigations until then (session.upload_progress.enabled=0, tuning memory_limit/post_max_size, blocking multipart, …) only work when set where they apply before request parsing, such as php.ini or the FPM pool. ini_set() and FPM .user.ini have no effect. The Step 2 report tells you where to change each server. Source: trends §2.6

FAQ

If the remote check says not_vulnerable_by_version, am I safe?

No. It only means the version shown in the headers meets the baseline; proxies and load balancers can mask the version, and SAPI and settings cannot be seen remotely. Make the final call from your server inventory and Step 2.

How do I check a server that hides its version (unknown)?

You can't from outside. On the server, check php -v and the package changelog, or run the Step 2 checker.

Can I check another company's site?

Not without permission. Even a single non-destructive GET, done systematically without authorization, may break computer-misuse laws. If you notice a problem on someone else's server, do not verify it yourself — notify the operator or your national CERT.

What does the tool collect or send?

Nothing. The remote checker sends one GET to the target you enter; the host checker makes no network requests. The report's transparency appendix lists every file it read.

Does it contain exploit (PoC) code?

No. It contains no payloads, exploits or bypass techniques, and does not link to exploit repositories.