Skip to content
Packstub

A checklist for Laravel apps after the October 2026 PHP and Node.js security releases

PHP and Node.js shipped security fixes on 21 October 2026. The versions a Laravel app needs, and where to check: FPM, workers, Octane, Docker, SSR, CI.

Published

On 21 October 2026, about an hour apart, Node.js and PHP both published security releases. PHP fixed two critical remote code execution vulnerabilities, and Node.js fixed ten issues, four of them rated high.

A single Laravel app often runs several copies of each runtime, so this guide gives you the minimum versions and then every place they tend to live. A Filament panel runs on the same PHP processes, so the same pass covers it. On Laravel Cloud, the PHP work was done for you, which leaves a deploy and your CI: the platform table below has the details for each host.

The guide draws on public write-ups. Laravel's post-mortem gives a candid, hour-by-hour account of the response, the Forge knowledge base has the step-by-step for Forge servers, and WorkOS wrote a clear roundup of the week.

The versions you need, at a glance

Runtime Minimum version What it fixes
PHP 8.2 to 8.5 8.5.12, 8.4.27, 8.3.36, 8.2.35 CVE-2026-109618 and CVE-2026-109619, both CVSS v4 9.2
PHP 8.1 and older Same version number, newer package revision (Forge's table) The same two CVEs, backported
FrankenPHP 1.13.2 or newer, ideally 1.13.4 Built with the fixed PHP versions
Node.js 26.12.1, 24.22.1, 22.23.4 Ten CVEs: four high, three medium, three low, including a Brotli flaw that can allow remote code execution

Two follow-ups to plan for:

  • 11 November: the Node.js project has announced another security release for 26.x, 24.x and 22.x, due on or shortly after that Wednesday, with a highest severity of high. The versions aren't listed yet, so treat the Node.js row above as the minimum for now and plan a second pass.
  • The next regular PHP bugfix release: PHP suggests keeping one session setting off until then. The session setting section helps you decide whether it applies to you.

What each Laravel platform handled

Platform PHP What's left for you
Laravel Cloud Patched in place, every region in under five hours, with no redeploy Nothing for PHP. Base images were rebuilt with patched PHP and Node.js, and a deploy is Laravel's usual way to pick up a new base image.
Laravel Forge Yours to update, server by server Everything in the checklists below
Laravel Vapor New runtimes and images published Redeploy your applications
Envoyer Laravel upgraded Envoyer's own servers Update the servers you deploy to. Laravel points Envoyer users to the Forge article for checking the version.

On any other host, the useful question is who owns the runtime. A managed runtime takes this work off your plate, and your own servers let you choose when and how each change lands. Either is a fine choice once you know which one you're on.

Every place PHP runs

Work down this list once per environment, staging and demo servers included. PHP's advisory covers all installations serving web requests, across PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. The advisory rates the risk highest for mod_php, so start there if you have any.

  • Every PHP version on each server. ls /etc/php lists them. Forge's advice is to patch all of them, including versions no site uses.
  • PHP-FPM and the CLI. They are separate binaries, so check both: php8.4 -v and php-fpm8.4 -v.
  • Queue workers, Horizon, Reverb and other daemons. Each keeps the old PHP until it restarts.
  • Octane. A full server restart suits a runtime change best, as explained below.
  • FrankenPHP. It carries its own PHP.
  • Docker images. Each one needs a rebuild and a redeploy.
  • Windows, if you run it. PHP rebuilt its Windows packages on 26 October with a Brotli fix, as 8.5.12-1, 8.4.27-1, 8.3.36-1 and 8.2.35-1.

Note

On Forge, automatic security updates don't patch PHP, because Forge installs it from a dedicated package repository. The Forge article walks through the update from the server's PHP tab, by SSH, or with a Recipe across many servers.

If you installed PHP from your distribution instead, its fix arrives under the distribution's own version numbering, so check its tracker (Ubuntu's, for example) rather than comparing with the table above.

PHP 8.1 and older show the same version before and after

The PHP project no longer ships releases for these lines. In the packages Forge installs, Ondřej Surý backported the fixes as new revisions, so php -v won't change. Compare the revision with Forge's table instead:

dpkg -l 'php8.1*' | awk '/^ii/ {print $2, $3}'

If you build from source, PHP published minimal backports for 7.4, 8.0 and 8.1. Either way the backport is a stopgap, and moving to a supported version is the lasting step.

Long-running processes need a restart

The package upgrade restarts PHP-FPM. Processes started from the CLI keep running the old PHP until you restart them. Forge lists these commands, one set for each application:

php artisan queue:restart
php artisan horizon:terminate
php artisan octane:reload

Octane needs a little more, which the next section covers. Add php artisan reverb:restart if you run Reverb, and php artisan pulse:restart for Pulse's daemons. Your process monitor brings each of them back.

To find anything you missed, list what's running with its start time. A process older than your patch still has the old runtime in memory:

ps -eo pid,lstart,command | grep -E '[a]rtisan|[n]ode '

Octane and FrankenPHP take one extra step

octane:reload restarts the application workers while the server process keeps running. That's ideal after a deploy. After a runtime change, a full restart through your process monitor (sudo supervisorctl restart <program>) also replaces the server process, which is where PHP lives on FrankenPHP and Swoole.

FrankenPHP needs a new binary first, because updating the system's PHP doesn't touch the copy it embeds. Octane's docs give the steps:

  1. Check the bundled version with ./frankenphp version.
  2. Delete the binary from the project root.
  3. Run php artisan octane:install --server=frankenphp to download the latest release.
  4. Restart Octane.

If you installed FrankenPHP system-wide or use its Docker image, update it the same way you installed it.

FrankenPHP 1.13.4 was the newest security release at the time of writing. Aim for that one: it also fixes worker-mode issues in FrankenPHP itself, including a crash that affects only 1.13.2 and 1.13.3.

Docker images stay on the PHP they were built with

A pinned digest or an exact tag such as php:8.4.26-fpm won't change until you edit it, and a floating tag such as php:8.4-fpm only moves when you pull it again. Update the FROM line if it's pinned, rebuild with a fresh base image, and read the version from the image itself:

docker build --pull -t my-app .
docker run --rm my-app php -v

Ask the running app which PHP serves requests

php -v tells you about the binary on disk. To see what serves requests, deploy a temporary route on a path only you know, open it, and then remove it:

// routes/web.php (temporary)
Route::get('/runtime-check-change-me', fn () => [
    'php' => PHP_VERSION,
    'sapi' => PHP_SAPI,
    'upload_progress' => ini_get('session.upload_progress.enabled'),
    'serialize_handler' => ini_get('session.serialize_handler'),
]);

The last two values are for the session setting covered further down.

Every place Node.js runs

npm update leaves Node.js as it was. As WorkOS puts it, upgrading an SDK "or any other npm package doesn't change the Node.js runtime".

Each place below needs a new Node.js binary or base image, installed the way the current one was. The new binary also brings the updated CA certificates, c-ares and Undici. End-of-life lines are affected as well, so this is a good moment to move to a supported line.

  • Inertia SSR. This is Node.js running in production next to your app. Update Node.js, then run php artisan inertia:stop-ssr and let your process monitor start it again. Add --graceful if the server might already be stopped.
  • Browsershot and Puppeteer. Spatie's Browsershot calls node by default. If you set a path with setNodeBinary(), make sure it points at the new version.
  • CI and build machines. Vite runs here. Update .nvmrc, the Node.js version in your CI config, and any FROM node: line.
  • Everything else under a process monitor. Small scripts and helpers count, and each one needs a restart.

Your config files show what you asked for, so WorkOS suggests also checking process.version inside the process. On a server, node -p process.version shows the binary on your PATH.

WorkOS also points out that the Brotli flaw (CVE-2026-111497) is most directly reachable through Node's built-in fetch(), which decompresses Brotli responses automatically. Code that decompresses user-supplied data is exposed too. Start with Node.js processes that do either.

The session upload progress setting from 23 October

Two days after the release, PHP published an informational advisory for CVE-2026-115560. PHP calls it unlikely in practice and will detail it in full with the next regular release. It needs all three of these at once:

  1. session.serialize_handler set to php_binary or php_serialize in configuration.
  2. The app switching it to php with ini_set() before session_start().
  3. Session upload progress still enabled.

Most Laravel apps won't match, since Laravel runs its own session layer. In the app we checked (Laravel 13.33, Livewire 4.4, Filament 5.9), those three packages contain no session_start() call and no reference to upload progress. Your own code and dependencies are what matter, so take a minute to look:

grep -rn "serialize_handler" app config routes bootstrap vendor --include='*.php'

A hit in Symfony's NativeSessionStorage is only its list of options. You're looking for an ini_set() that changes the handler. The temporary route above shows the configured handler, and PHP's default is php.

PHP suggests turning the feature off until its next regular bugfix release, and also says apps that never change the handler at runtime can keep it on. If your search finds a match, or you'd rather close the path entirely, turn it off:

session.upload_progress.enabled = 0

Set it in php.ini or the FPM pool and restart every worker. PHP says not to rely on ini_set() or FPM's .user.ini for this one.

If you already set it on 21 October, keep it in place: PHP's advisory from that day lists the same setting, along with others, for servers that can't update right away. PHP is clear that those measures reduce exposure to specific attack paths and don't make an installation safe, so the update remains the complete fix.

When you can skip part of this

The checklist is wider than most apps need, and a few cases shorten it:

  • On Laravel Cloud, the PHP work was done for you. That leaves Node.js: a deploy to pick up the rebuilt base image, plus your CI.
  • With no Node.js in production, the SSR and Browsershot lines fall away and CI remains.
  • With no Octane, Reverb or Docker, those lines don't apply.

Skip a line only because the thing isn't there. The 23 October setting is the one optional step here, and a stopgap never replaces the update.

Habits worth keeping from these write-ups

Laravel and WorkOS also wrote down what they plan to keep doing, and most of it scales down to a small team.

  • Keep a list of what runs where. Laravel is tracking the exact runtime of each Cloud application more strictly. For a small team, a short file in the repo works: each server, its PHP and Node.js versions, its daemons, its images. The next round becomes a walk down that list.
  • Follow the announcements. PHP's pre-announcement came the day before its release, and Node.js has given notice of 11 November in advance. The PHP news feed and the Node.js vulnerability feed both work in any reader.
  • Stay on supported versions. A patch for a supported line is a routine upgrade. Laravel is removing end-of-life versions from Cloud, and Forge recommends the same move.
  • Have a first step that doesn't depend on the patch. Laravel turned on Cloudflare's managed firewall rules hours before the PHP release. As they say, the rules reduce exposure and don't replace the patch.
  • Give urgent work its own queue. Forge now runs deployments on their own queue, so a surge of other jobs can't hold them up. The same idea works in your own Horizon setup.
  • Wait a little before saying "fixed". Laravel is adding a soak period, a stretch of watching things stay healthy, before announcing a recovery. A second check does the same for your own message to customers.
  • Let new packages settle. WorkOS waits seven days by default before installing new package versions, with careful exceptions for urgent security fixes.

Where to start

Open the table at the top next to your list of servers, and work through production first, then staging, then CI. If a public server stayed on an old version for a while, read through its logs while you're there, and write down what you updated and when.

Then put a reminder in your calendar for 11 November, when the Node.js project's next release is due.