php2shell.site active development

php2shell check — patch & mitigation status for CVE-2026-109618 / CVE-2026-109619, two critical unauthenticated remote-code-execution bugs in PHP, for URLs you are authorized to test. All verdict logic runs locally in your browser — the server only relays raw HTTP facts.

advisory out now — update PHP php.net, 21 Oct 2026: Critical remote code execution vulnerabilities, update now · details ▾
Fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 (source, Windows; Linux distributions and LTS vendors got the patches in advance — check your vendor). At risk: every PHP installation serving web requests — PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed; highest for mod_php, where an unauthenticated request can trigger the attack before any application code runs.
CVE-2026-109618 (GHSA-w8hw-w9fx-j79w): RCE via out-of-memory corruption during request setup. CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp): RCE via stale global state reused by a later request on the same worker.
PHP 8.1 and older get no release from the PHP project: use your vendor’s backport or upgrade; minimal source backports exist for 7.4, 8.0 and 8.1. Using rpms.remirepo.net? It has no update today — switch to distribution packages or build from source.
If you cannot update immediately (reduces exposure, does not make PHP safe)
CVE-2026-109618 (OOM corruption):
  • memory_limit=-1, set where applications can’t override it (e.g. php_admin_value in the FPM pool or Apache config); make sure no pool/directory/app setting brings a finite limit back.
  • Low post_max_size: 8M without file uploads, 32M with them; keep upload_max_filesize below it. Also limit decoded request size, field count, multipart part count, header count and nesting depth at the web server / proxy — including requests without a usable Content-Length.
  • Container / cgroup memory limit as an availability boundary (ideally killing only the affected worker). Do not use RLIMIT_AS / RLIMIT_DATA — they can cause the vulnerable allocation failure.
CVE-2026-109619 (stale global state):
  • session.upload_progress.enabled=0 in php.ini, the FPM pool or server config (applies before request parsing), then restart every worker. Not via ini_set() or FPM .user.ini. Blocks the confirmed session paths only.
  • PHP 8.5: fatal_error_backtraces=0 and restart every worker (blocks the confirmed backtrace path only).
  • Remove invalid/deprecated per-request settings that emit diagnostics before initialization — hiding them (error_reporting, display_errors, @) does not help.
  • Fix attacker-reachable fatal errors and execution timeouts (callbacks, upload/import processing, cleanup).
DIY: Run the curl test script yourself

Want to run the exact same inert checks yourself directly from your terminal or CI? Below is the curl test script representing the 7 requests (1 GET + urlencoded & multipart across POST, PUT, and PATCH). It never sends upload-progress fields or file parts, so it is safe to run on authorized targets.

Bash / curl script

        
How to interpret the output:
  • X-Powered-By / Server header: Look for PHP version info (fixed releases: 8.2.35+, 8.3.36+, 8.4.27+, 8.5.12+).
  • Multipart 403 / 406 while urlencoded succeeds (200/302/405): Multipart is blocked by WAF/CDN/web server rule before PHP processes it (MITIGATED — UPDATE STILL NEEDED).
  • Multipart 200 / 3xx: Multipart request body reaches the application (ASSUMED VULNERABLE if unpatched).
  • All 405 Method Not Allowed: if the 405 responses carry no PHP signs (no PHPSESSID cookie, no X-Powered-By) the server refused before PHP (MITIGATED — UPDATE STILL NEEDED, or NO PHP DETECTED without any PHP indicators). A 405 that sets a PHP session cookie came from PHP itself, after it read the upload (ASSUMED VULNERABLE).

How to read. PHP detection: an X-Powered-By: PHP/… header (only PHP itself counts, not Next.js/Express/KPHP) or a PHP session cookie on any response; the version is compared with the patched-release list shown above the result (kept server-side by the operator). Absent banners (CDN stripping, expose_php=Off) report unknown — a missing banner is not safety. Block test: an upload-style (multipart) request vs a normal form POST, on POST, PUT and PATCH — blocking POST alone is not enough, PHP 8.4 apps can read multipart on other methods too. ASSUMED VULNERABLE (red) means such requests flow through to the backend and no patched runtime could be confirmed — treat the site as vulnerable until a patched PHP version is verified. NO PHP DETECTED means no POST-shaped request is processed at this URL (connections dropped or 405/501 replies) and there are no PHP indicators (banner, session cookie) — consistent with a static site: nothing to exploit at this URL.

Probes. One URL at a time, seven inert requests (1 GET, then a normal + multipart request per method — never an upload-progress field, never a file part, so the vulnerable code path is never engaged). Redirects are followed like a browser (301/302/303 convert to GET, 307/308 keep the method, max 3 hops) — the first-hop status decides the verdict. A rejection at the CDN/WAF stops the request before PHP parses the body; the exact same status produced inside the application happens after — and the two cannot be told apart remotely, so the checker says so instead of over-claiming. A CDN-block also does not help if the origin server is directly reachable. A URL that refuses connections shows green OFFLINE — nothing is serving there, so there is nothing to assess.

Scope. This is a patch-status / configuration check, not a vulnerability probe: it never sends exploit-shaped requests (no session cookie, no file part, no upload-progress field, no stalling). Results live only in your browser session — there is no export endpoint; the tested URL stays in the address bar as /… for bookmarking/sharing and is never sent anywhere. Every submission and every poll solves a small proof-of-work in your browser (an abuse brake, ~1s once per check). Definitive fix = a patched PHP runtime.

No guarantees. Results are best-effort indications from the outside: banners can lie, caches can hide the origin, and edge behavior differs per route. This is not a vulnerability assessment — verify on the host. Docs for humans and LLMs: llms.txt.