Insights/

php2shell: check your PHP servers

Two critical PHP bugs, CVE-2026-109618 and CVE-2026-109619, let an attacker run code on a PHP web server without logging in. Upgrade to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 and restart your PHP workers.

CVSS v4.0 9.2 CriticalExploit attempts seenDisclosed 21 Oct 2026

What happened

On 21 October 2026 the PHP project shipped emergency releases for two bugs in how PHP sets up and tears down a web request. Both are rated CVSS v4.0 9.2 (Critical) and both need no login. CVE-2026-109619 needs no particular application code on PHP-FPM; CVE-2026-109618 was shown on a default mod_php setup.

CVE-2026-109618 (GHSA-w8hw-w9fx-j79w)

Memory corruption when PHP runs out of memory while it is still preparing the request data. Multipart parsing (file uploads and form posts) can trigger it. The researchers showed unauthenticated remote code execution on a default mod_php setup; PHP-FPM, FrankenPHP and LiteSpeed (LSAPI) are likely exposed too. Advisory.

CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp)

A use-after-free: state from one request survives into the next request handled by the same worker. That gives remote code execution or memory disclosure. It was shown on mod_php (8.5 with fatal_error_backtraces) and on PHP-FPM through session upload progress, which is on by default. Advisory.

Cloudflare and watchTowr reported exploit attempts on 21 October. The bugs were not in CISA's Known Exploited Vulnerabilities catalog as of that date. Be careful with "PoC" code circulating for php2shell: some of it is malware.

Who is affected and fixed versions

Every PHP web SAPI: PHP-FPM, mod_php, php-cgi, FrankenPHP and LiteSpeed. PHP used only from the command line (cron jobs, Composer, build steps) is not the attack surface. This is a bug in the PHP runtime, not in a Composer package, so composer.lock tells you nothing: you need the version of the PHP binary that serves requests.

Fixed releases published 21 Oct 2026, 14:00 UTC.
BranchFixed inStatus
8.58.5.12Official release, 2026-10-21
8.48.4.27Official release, 2026-10-21
8.38.3.36Official release, 2026-10-21
8.28.2.35Official release, 2026-10-21
8.68.6.0RC4Fix included in the release candidate
7.4, 8.0, 8.1No official releaseSource backports from the PHP security team; distro and LTS vendors ship patched packages that keep the old version string
5.x to 7.3NoneEnd of life, no fix: treat as vulnerable

If you run PHP from Debian, Ubuntu, RHEL or another distro, or from an LTS vendor, the patched package may keep the old upstream version string (for example 7.4.33-1+ubuntu20.04). Check your vendor's advisory for the package version that carries the fix.

Check a site's public header

Enter a URL. We send a HEAD request (GET if HEAD is refused, body discarded), no cookies and no body, follow up to 3 redirects on public hosts, and read the PHP version the server advertises in X-Powered-By or Server, if any. To refuse private addresses we look the hostname up over DNS-over-HTTPS (Cloudflare) first. Only check sites you own or operate.

  • It only reads a public header. It does not test for the bug and sends nothing that could trigger it.
  • Most sites hide the header (expose_php = Off). Then the answer is "unknown", which says nothing either way: run the skill below on the server.
  • A header can be stale or wrong (a proxy, a CDN, a distro backport under the old version). Treat the result as a hint, not a verdict on the server.

Check properly with your agent

The php2shell-check skill runs on the machine (or in the repo) and checks what actually serves requests: the PHP runtime version, Dockerfile FROM php: tags, .php-version, the PHP constraint in composer.json, and the stopgap ini settings. It flags distro builds that may carry a backport under an old version string, and gives your agent the upgrade plan.

npx vskill@latest install anton-abyzov/vskill/php2shell-check

Then ask your agent: "check this server for php2shell". The skill is in the vskill repository.

Stopgaps until you can upgrade

These reduce exposure but do not fully fix either bug. Upgrade as soon as you can, and restart PHP workers after any change.

CVE-2026-109618

  • Set memory_limit = -1 with php_admin_value (so scripts cannot change it).
  • Set post_max_size = 8M if you accept no uploads, or 32M if you do, and keep upload_max_filesize below post_max_size.
  • Do not cap memory with RLIMIT_AS or RLIMIT_DATA.

CVE-2026-109619

  • Set session.upload_progress.enabled = 0 in php.ini or the FPM pool with php_admin_value. ini_set() and .user.ini do not work for this.
  • On PHP 8.5, set fatal_error_backtraces = 0.
  • Where performance allows, set pm.max_requests = 1 so no worker serves a second request.
; FPM pool (e.g. /etc/php/8.x/fpm/pool.d/www.conf), for a site that accepts uploads.
; With no uploads use post_max_size = 8M.
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 16M
php_admin_value[session.upload_progress.enabled] = 0
; PHP 8.5 only
php_admin_value[fatal_error_backtraces] = 0
; Where performance allows: one request per worker
pm.max_requests = 1

Get told about the next one

We are building CVE watch: it tracks the runtimes and packages your projects use and emails you when a critical advisory lands, with the fix plan for your stack. Join the waitlist and we will tell you when it opens.

Sources

  1. PHP security advisory GHSA-w8hw-w9fx-j79w (CVE-2026-109618)
  2. PHP security advisory GHSA-6wmf-4rv5-p3rp (CVE-2026-109619)
  3. php.net release announcements
  4. NCSC: critical security issue affecting PHP
  5. CERT-EU security advisory 2026-018
php2shell check: CVE-2026-109618 and CVE-2026-109619 | Verified Skill