Blog/Security

PHP security update: patch the October RCE bugs

S
Schoolabe Team
12 min read

Written by the Schoolabe Team on 23 October 2026. We publish practical guides for students and working developers. This post summarizes public advisories from php.net and the PHP Foundation. It is not an original vulnerability report.

On the morning of 21 October 2026, a Laravel shop can still be on PHP 8.3.30 while the PHP project tells every web install to update. The release fixes two critical remote code execution bugs. Two days later, on 23 October, PHP added a narrower note about session upload progress.

PHP remote code execution here means a request that has not logged in can reach code execution on the server. The PHP project says the risk is highest on Apache with mod_php, where a demonstrated exploit can run before any application code. PHP-FPM, php-cgi, FrankenPHP, and LiteSpeed are in scope as well.

If you keep one action from this page, install PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35, then restart the workers that answer HTTP. The project says there is no complete mitigation. Config changes reduce some paths. They do not make an old build safe.

What the PHP security update fixes

The 21 October releases fix two bugs in code almost every request touches: memory handling and error handling.

CVE-2026-109618, also tracked as GHSA-w8hw-w9fx-j79w, is remote code execution through out-of-memory corruption. PHP uses longjmp() when an allocation fails, so it can abandon the current request. In some moments, request memory is reachable before it is fully initialized. If an allocation fails then, PHP does not account for that early exit. Later cleanup can treat the broken data as valid. The GitHub advisory says several out-of-memory strategies can trigger this consistently.

CVE-2026-109619, also tracked as GHSA-6wmf-4rv5-p3rp, is remote code execution through stale global state. Request-owned internal state can remain after the memory behind it has been freed. A later request on the same worker can use that stale state before normal startup clears it. The PHP Foundation says a use-after-free and a worker crash were confirmed, and the reporter demonstrated code execution against a real application on Apache with mod_php.

Both issues were hard to patch because they sit in the center of the engine. A careless change could break compatibility, slow requests, or disturb third-party extensions. That is why this is a security release, not a feature release.

Patched versions, as published on 21 October 2026:

  • PHP 8.5.12
  • PHP 8.4.27
  • PHP 8.3.36
  • PHP 8.2.35

PHP 8.6.0 RC4, also dated 21 October, contains the same fixes. The project says not to run that build in production. The next candidate, RC5, is planned for 5 November 2026.

Who has to install it

The PHP project lists every installation that serves web requests: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP, and LiteSpeed. A CLI script that nobody can reach over HTTP is a different situation. A public WordPress, Laravel, Symfony, or custom PHP site is in the set they named.

They call out mod_php as the highest risk, because an unauthenticated request can trigger the attack before application code runs, with a demonstrated exploit on default settings. PHP-FPM is not a free pass. The Foundation says code execution was also confirmed on PHP-FPM through application-level paths.

Shared hosting is awkward. You may not control the package. You still need the version the site actually runs, which can differ from a marketing email. Ask the host which build they installed after 21 October 2026, and confirm it on the version screen or a temporary phpinfo() page that you delete afterwards.

PHP 8.1 and older no longer receive updates from the PHP project. Some distributions and long-term support vendors backport fixes. If you compile PHP yourself and have no vendor, the security team published minimal source backports for PHP 7.4, 8.0, and 8.1. Those backports are a bridge. They are not a plan to stay on an unsupported line.

PHP 8.2 reaches end of life on 31 December 2026. The 8.2.35 notes say it will get no further security fixes after that date. Install 8.2.35 now if you are still on 8.2, and schedule the move to 8.3 or newer before the year ends.

How a request can exhaust memory without looking oversized

You do not need an upload that obviously exceeds post_max_size. The GitHub advisory for CVE-2026-109618 describes multipart cases that can exhaust memory while appearing to fit the limit.

A multipart body without a usable Content-Length can pass the first post_max_size check and keep sending decoded data.

One part can carry a large number of headers. PHP's in-memory copy of those headers can cost more than the bytes on the wire, so a request inside post_max_size can still hit memory_limit.

Empty file fields do not count toward max_file_uploads, but they still build the usual file metadata arrays. Nested field names multiply that work.

Application code can also force a large allocation from input an outsider controls. The advisory says the failed allocation does not have to be the same one as the memory that ends up invalid. Request shutdown then reads or branches on that state.

This page does not include a request that triggers the bug. The operator lesson is smaller: a memory_limit you set to protect the box can be the condition that reaches the flaw, and a request that looks "within limits" can still get there.

How one worker can carry state into the next request

PHP-FPM and similar servers reuse a worker for many requests. That reuse is normal. It is also why CVE-2026-109619 matters. If a fatal error lands at the wrong moment, internal state can still point at memory from the previous request. The next request on that worker may use it before initialization runs.

The confirmed paths in the 21 October advisory involve session upload progress and, on PHP 8.5, fatal error backtraces. The project is plain that turning those off blocks the confirmed paths, not every variant.

Invalid or deprecated settings applied per request can emit diagnostics before initialization. Hiding those messages with error_reporting, display_errors, or the @ operator does not remove the problem. The diagnostic still happens.

Fatal errors and timeouts an outsider can reach belong on the same list: failures in callbacks, upload or import handling, and cleanup. Fix them in the application. Do not file them as log noise and move on.

The 23 October note on session upload progress

On 23 October 2026, PHP published an informational advisory for CVE-2026-115560. The suggestion is to keep session.upload_progress.enabled=0 until the next regular bugfix release.

This vector is narrower than the two critical bugs. PHP says it can occur only when three conditions line up.

The application sets session.serialize_handler to php_binary or php_serialize in configuration.

It then switches that handler to php at runtime with ini_set(), before session_start().

Session upload progress is still enabled.

An application that never changes the serialize handler at runtime can leave upload progress on. PHP judged this combination uncommon enough for the normal release cycle, and said a full advisory would ship with that release.

If you already disabled upload progress for CVE-2026-109619, leave the setting in place. Put it in php.ini or the FPM pool, then restart workers. ini_set() and a per-directory .user.ini run too late for paths that execute before request setup.

Update PHP, then prove which binary answers HTTP

A package on disk does nothing until the process that answers requests is the new binary. php-fpm, Apache, and queue workers are separate processes. Restart each one that still has the old build loaded.

On Debian or Ubuntu, read the vendor changelog. Many vendors received the patches before the public release. Their package version may not read 8.3.36 even when the fix is present. Look for CVE-2026-109618 and CVE-2026-109619 in that changelog, not only for an upstream version string.

If you build images yourself, pull a base image published after the release or compile the matching version. Restart the container. A floating tag such as php:8.3-fpm can stay cached on a node and keep serving the old layers.

Windows source and binaries are on the PHP downloads page next to the source tarballs.

After the restart, check the version the site sees. php -v in a shell can be a different binary from the one Apache or FPM uses. A one-line phpinfo() page, deleted after you read it, or the host's PHP version screen, is the check that counts. A public phpinfo() page is its own leak, so do not leave it up.

Then click through the site: login, one form post, one file upload if you use them, and a queue worker if you run something like php artisan queue:work. Workers do not restart because you reloaded the web pool.

ini
; Pool config, not a runtime ini_set()
php_admin_value[session.upload_progress.enabled] = 0

That snippet is a precaution while you patch, not a substitute for the new version.

If the update has to wait until tomorrow

The PHP project says only an update is a complete fix. Use the steps below to shrink specific paths during a delay. Book the real upgrade. Do not treat the config as the finish line.

For CVE-2026-109618, the advisory suggests three temporary measures.

Set memory_limit=-1 in a place the application cannot override, such as php_admin_value in the FPM pool or the Apache config. Then search pool files, directory settings, and the app for a finite limit that puts the cap back. This removes the controllable PHP memory-limit failure. An allocation failure underneath can still reach the vulnerable path.

Lower post_max_size. If the app does not need uploads, the advisory uses 8M. If it does, 32M, with upload_max_filesize kept below post_max_size. Also cap decoded body size, field count, multipart part count, header count, and nesting at the proxy or web server. Those caps have to cover requests that omit a usable Content-Length.

A container or cgroup limit can bound damage when it kills only the affected worker. Do not substitute RLIMIT_AS or RLIMIT_DATA. The advisory says those limits can cause the allocation failure the bug depends on.

For CVE-2026-109619:

Set session.upload_progress.enabled=0 and restart every worker, from php.ini or the pool.

On PHP 8.5, set fatal_error_backtraces=0 and restart workers. That blocks the confirmed backtrace path only.

Remove invalid or deprecated per-request settings that print diagnostics before initialization.

Fix fatal errors and timeouts an outsider can trigger, including callback, upload, import, and cleanup failures.

What a patched binary does not cover

A new PHP build does not review your application for SQL injection, an old WordPress plugin, or a publicly writable uploads directory. Those are separate defects. Patching the engine is the job this week. It is not the whole security program.

memory_limit=-1 trades one risk for another. One request can use as much RAM as the machine allows, until a cgroup or the kernel stops it. Use the unlimited setting as a short bridge, and keep a real memory boundary outside PHP.

Turning session upload progress off disables a feature some large-upload screens use to draw a percent bar. If a form depends on that bar, test it after the change. If you are unsure whether the app switches session.serialize_handler at runtime, PHP's 23 October note still says to leave the feature off until the bugfix release.

The minimal source backports for PHP 7.4, 8.0, and 8.1 are not a support contract. Unsupported PHP misses later fixes. Put the upgrade on a ticket with an owner and a date.

I have not reproduced the exploits described in the advisories. Versions, dates, and config notes here come from the PHP news archive, the PHP Foundation post on 21 October 2026, and GHSA-w8hw-w9fx-j79w. If a vendor changelog disagrees with an upstream version number, trust that changelog for the package and still confirm both CVE IDs are listed.

A check you can finish this afternoon

  1. Write down the PHP version the public site is serving, not the version on your laptop.
  2. Match it to 8.5.12, 8.4.27, 8.3.36, or 8.2.35, or to a vendor package that names CVE-2026-109618 and CVE-2026-109619.
  3. If you are below those versions, schedule the package update and a full worker restart.
  4. If the update slips to tomorrow, set session.upload_progress.enabled=0 in the pool and restart workers. Change post_max_size and memory_limit only if you accept the tradeoff above.
  5. If you are on PHP 8.1 or older, open a ticket to move to a supported release. Do not stop at the backport.
  6. If you are on PHP 8.2, put 31 December 2026 on the calendar. That is the last day the 8.2 line receives security fixes.

FAQ

Which PHP versions fix the October 2026 remote code execution bugs?

As of 21 October 2026, the fixed releases are PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35. PHP 8.6.0 RC4 includes the fixes and is a test build, not a production release.

Does this affect WordPress and Laravel?

Yes, when they run on an unpatched PHP that serves web requests. The bugs are in PHP, not in one framework. Update the runtime the site uses, then restart PHP-FPM or Apache.

Is session.upload_progress.enabled=0 enough?

No. That setting blocks confirmed paths for CVE-2026-109619 and is the precaution PHP suggested on 23 October for the narrower CVE-2026-115560. It does not replace the version update.

What if the host will not say which CVE they patched?

Ask for the package changelog. A version number alone can be misleading when a distribution backports fixes. You want the two CVE IDs, plus a restart of the workers that serve the site.

Where is the official write-up?

The 21 October advisory and the 23 October session note are on the PHP news archive for 2026. The PHP Foundation explained both bugs in its 21 October post. The out-of-memory issue is GHSA-w8hw-w9fx-j79w.

Related on Schoolabe: AI agent security bugs from October 2026.