Patch PHP2Shell, then restart, rotate and re-scan.
Pick your platform, SAPI and PHP branch to get the exact upgrade, restart and verify commands, with the target version filled in from the live php.net data. Then apply the interim mitigations and work the after-patch checklist.
There is no complete mitigation. Updating is the only safe choice.
These two bugs were exploited in the wild before the patch shipped. Upgrade to the fixed release for your branch, restart every worker, then assume secrets may have leaked.
--only-upgrade touches only php8.4 packages that are already installed. The ondrej/php PPA ships the fixed build; if apt reports no candidate, confirm the PPA is enabled and the fixed version is visible with apt-cache policy php8.4-fpm.
Restart
Restart (PHP-FPM)
sudo systemctl restart php8.4-fpm
Verify
Confirm the fixed version is live
php8.4 -v
php8.4 -r 'echo PHP_VERSION, PHP_EOL;'
The version a browser sees can differ from the CLI; confirm every SAPI reports 8.4.27 or newer.
Confirm the reported version is 8.4.27 or newer.
If several PHP branches are installed, repeat for each; update-alternatives --list php shows which binary php resolves to.
These reduce exposure while you roll out the upgrade. php.net is explicit that they are not complete: "There are no complete mitigations, updating is the only safe choice." Apply them as php_admin_value / php_admin_flag (FPM pool) or php_admin_value (Apache) so applications cannot override them, then restart every worker. Remove the ones you do not otherwise want once every worker runs the patched build.
Remove the memory limit (make OOM less reachable)
FPM pool (/etc/php/8.4/fpm/pool.d/www.conf) or Apache vhost
Remove the memory limit (make OOM less reachable)
; PHP-FPM pool
php_admin_value[memory_limit] = -1
The primary configuration mitigation, and not a complete one. Set it so applications cannot override it and restart every worker.
With no limit a single request can use all memory; watch memory and put a sane limit back once you have patched.
log_errors = On
error_reporting = E_ALL
error_log = /var/log/php/error.log
Set these in startup configuration to surface warnings and fatal errors an attacker could reach in callbacks, uploads, imports and cleanup. An empty log is not proof of safety.
Consider pm.max_requests = 1 if you can afford the performance cost.
An upgrade only protects new processes, and it does not undo a break-in that already happened. Work through this once every worker runs the fixed build.
Restart every PHP worker and web server
The patched binary only loads in fresh processes. PHP-FPM pools, Apache mod_php, LiteSpeed lsphp, FrankenPHP workers, php-cgi processes and queue workers (Horizon, Supervisor, long-lived cron children) that started before the upgrade still run the old, vulnerable code. Restart them all and confirm start times are newer than the upgraded binary.
CVE-2026-109619 includes an unauthenticated memory-disclosure path. On any host that was internet-facing before you patched, treat secrets readable by the web worker as potentially exposed and rotate them: database passwords, APP_KEY / app secrets, third-party API keys, OAuth client secrets, mail credentials, and any crypto or Solana private keys, seed phrases or mnemonics in the environment or on disk. Revoke the old values, do not just add new ones.
Both CVEs were exploited in the wild before the patch shipped, so patching does not undo a prior break-in. Run a full scan for webshells, modified framework and core files, PHP inside upload directories and exposed keys, and review web server access and error logs around the exposure window for anomalies.
Once every worker runs the patched build, restore memory_limit, post_max_size and max_input_nesting_level to normal values so the host is not left fragile. Keep session.upload_progress off and (on 8.5) fatal_error_backtraces off if you do not use them.
Check the CLI, every FPM pool and the web-facing runtime. The version a browser sees can differ from the CLI. Confirm each reports the branch's fixed release or newer.