Skip to main content

PHP RCE

Severity · CriticalCVSS v4.0 · 9.2PHP · web SAPIs

Two bugs in how PHP sets up and tears down a request let an unauthenticated request run code on the server. php.net fixed both on 2026-10-21 and asks every PHP user to update immediately.

Every PHP install that serves web requests is at risk: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. php.net rates mod_php highest: it has a demonstrated exploit that triggers before any application code runs.

The two CVEs

CVE-2026-109618 — RCE via out-of-memory corruption. Out-of-memory handling can interrupt PHP while request data is only partly initialized, and request cleanup then treats it as valid.

CVE-2026-109619 — RCE via stale global state. Request-owned state can survive after its memory is freed, and a later request on the same worker can use it before normal initialization resets it.

Timeline

  • 10-20 php.net gives advance notice of a release for two critical bugs, both CVSS v4.0 9.2.
  • 10-21 CERT-EU publishes advisory 2026-018.
  • 10-21 14:00 UTC — PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 ship, with source backports for 7.4, 8.0 and 8.1.
  • 10-21 Ubuntu USN-8948-1 ships fixed builds for 22.04, 24.04, 26.04 and 26.10.

Fixed versions

  • 8.5 → 8.5.12, 8.4 → 8.4.27, 8.3 → 8.3.36, 8.2 → 8.2.35.
  • PHP 8.1 and older get no release from php.net: use your vendor's backport, or build from php.net's source backports for 7.4, 8.0 and 8.1.
  • Distributions received the patches in advance and backport them without changing the PHP version, so a distro build below these numbers may already be fixed.

Partial mitigations

php.net says these reduce exposure to the demonstrated paths but do not make an installation safe. Set them where applications cannot override them, then restart every worker:

  • memory_limit = -1 (CVE-2026-109618), and never cap memory with RLIMIT_AS or RLIMIT_DATA.
  • post_max_size of 8M, or 32M if you take uploads (CVE-2026-109618).
  • session.upload_progress.enabled = 0 in php.ini or the FPM pool, not ini_set() (CVE-2026-109619).
  • PHP 8.5 only: fatal_error_backtraces = 0 (CVE-2026-109619).
  • Otherwise, keep internet-facing PHP off public networks until it is patched.

References

01Am I affected?

A host is likely exposed if any of these is true:

  • It serves web requests through PHP-FPM, mod_php, php-cgi, FrankenPHP or LiteSpeed on an upstream build below 8.5.12, 8.4.27, 8.3.36 or 8.2.35 for its branch.
  • It runs PHP 8.1 or older without a vendor backport.
  • Its distro PHP package predates the vendor's fix. The version alone does not tell you: check the vendor's advisory for the exact build.
  • It installs PHP from rpms.remirepo.net, which php.net said would not have updates on 2026-10-21.
  • It runs container images built on a PHP release from before 2026-10-21.

Upgrading the package is not the end: PHP workers keep running the old code until they are restarted.

02Install Swamp

The @swamp/cve/php-rce-2026-10 extension finds every PHP binary, PHP-FPM, mod_php, php-cgi, FrankenPHP and LiteSpeed install on a host, with its package, and gives each a verdict. Distro builds below the upstream fix that no security tracker marks fixed are reported as check-vendor, never guessed. scan needs no root and changes nothing.

Install Swamp:

curl -fsSL https://swamp-club.com/install.sh | sh

Initialize a new repo (run this in a new empty directory):

swamp repo init

Pull the scanner:

swamp extension pull @swamp/cve/php-rce-2026-10

Create the scanner, with the SSH user and key it uses for remote hosts:

swamp behavior create @swamp/cve/php-rce-2026-10 php-rce-scanner \
    --global-arg sshUser=ubuntu \
    --global-arg sshKey=~/.ssh/id_ed25519

Am I affected (this machine):

swamp behavior run php-rce-scanner scan

Mitigate (a dry run unless you pass dryRun=false):

swamp behavior run php-rce-scanner mitigate

Set dockerContainer or dockerImage with --global-arg on a new behavior to scan a container or an image instead. Windows hosts are scanned over SSH, and never changed.

03Scan your fleet

Pass a comma-separated list of hosts and the scanFleet method scans each one in parallel over SSH. A host it cannot reach is reported as unreachable, and the rest are still scanned:

swamp behavior run php-rce-scanner scanFleet \
    --input hosts=192.0.2.10,192.0.2.11

04Scan Results

A real scan of the official php:8.2.34-apache image, running as a container named shop-web:

# PHP RCE Scan Results (CVE-2026-109618, CVE-2026-109619)

1 host(s) scanned: 1 affected, 0 to check with the vendor, 0 patched or without
PHP

┌─────────────────┬────────┬─────────────────────┬────────────┬────────┬──────────┬───────────────┐
│ Host            │ PHP    │ SAPIs               │ Verdict    │ Public │ Risk     │ Action        │
├─────────────────┼────────┼─────────────────────┼────────────┼────────┼──────────┼───────────────┤
│ docker-shop-web │ 8.2.34 │ cli, apache2handler │ vulnerable │ no     │ CRITICAL │ rebuild-image │
└─────────────────┴────────┴─────────────────────┴────────────┴────────┴──────────┴───────────────┘

## Installs needing attention

┌─────────────────┬────────────────────────────────────┬────────────────┬─────────┬─────────┬────────────┬───────────────┐
│ Host            │ Install                            │ SAPI           │ Version │ Package │ Verdict    │ Action        │
├─────────────────┼────────────────────────────────────┼────────────────┼─────────┼─────────┼────────────┼───────────────┤
│ docker-shop-web │ /usr/local/bin/php                 │ cli            │ 8.2.34  │ —       │ vulnerable │ rebuild-image │
├─────────────────┼────────────────────────────────────┼────────────────┼─────────┼─────────┼────────────┼───────────────┤
│ docker-shop-web │ /usr/lib/apache2/modules/libphp.so │ apache2handler │ 8.2.34  │ —       │ vulnerable │ rebuild-image │
└─────────────────┴────────────────────────────────────┴────────────────┴─────────┴─────────┴────────────┴───────────────┘

## Recommendations

    * Rebuild this container's image (PHP 8.2.34) on PHP 8.2.35 or newer and redeploy; containers are not changed in place.
    * Until upgraded, the advisories' partial mitigations for official are session.upload_progress.enabled=0, memory_limit=-1 (set them in the image's php.ini until it is rebuilt). They do not make PHP safe.

Fixed upstream releases: 8.2.35, 8.3.36, 8.4.27 and 8.5.12. Distro verdicts use
the tracker snapshot from 2026-10-21T15:16Z. No indicators of compromise have
been published; log counts are hints only.

05Mitigate across your fleet

The mitigate method re-scans each host and skips the ones with nothing to do. On the rest it upgrades every installed PHP runtime package through apt, dnf, yum or apk, restarts the running PHP-FPM units, and Apache when mod_php is installed, then scans again. Containers are reported for an image rebuild and never changed in place.

Mitigation needs root, or passwordless sudo for the exact commands the dry run prints. If sudo would ask for a password, the host is reported as needs-privilege and nothing is changed. Restarting PHP-FPM or Apache briefly interrupts the requests they serve.

dryRun defaults to true — the method shows the plan and changes nothing. Pass dryRun=false to apply:

swamp behavior run php-rce-scanner mitigate \
    --input hosts=192.0.2.10 \
    --input dryRun=false

Where no fixed package exists yet, add applyConfigMitigations=true to also write php.net's partial ini mitigations. They do not make PHP safe.

06Mitigation Results

A dry run on the same container: mitigate never changes a container, and reports the image to rebuild.

# PHP RCE Mitigation: DRY RUN

┌─────────────────┬──────────────────┬────────────┬──────────┬───────────────┐
│ Host            │ Outcome          │ Privilege  │ Risk now │ Action        │
├─────────────────┼──────────────────┼────────────┼──────────┼───────────────┤
│ docker-shop-web │ no-automatic-fix │ not-needed │ CRITICAL │ rebuild-image │
└─────────────────┴──────────────────┴────────────┴──────────┴───────────────┘

## docker-shop-web

    * Target is a container: rebuild its image on a fixed PHP release instead of changing it in place.