PHP2Shell: What PHP Developers Must Do After the Host Patches
October 23, 2026 0 comments
PHP2Shell is the nickname for two critical PHP engine bugs (CVE-2026-109618 and CVE-2026-109619) that let an attacker without a login run code on a PHP server. The fix is a PHP update, not a PrestaShop, Magento or Laravel update. Once your host patches PHP, a handful of app-side checks still belong to your development team, and this post walks through them.
Last updated: October 23, 2026. This story is still moving, and we’ll revise this post as framework vendors and hosts publish more.
Want it on one page for your team or your host? Download the PHP2Shell checklist (PDF). It has every check and command from this post, with tick boxes.
In this post
Every hosting company spent this week sending the same email: update PHP. That’s correct, and it’s also where most of the coverage stops. cPanel shipped patched builds, the security vendors published their notes, and the people who actually maintain the PrestaShop store or the Laravel app were left with a question nobody answered for them. Is the host’s update the end of it?
No. It’s the most important part, but it isn’t the end. A few of the conditions these bugs rely on live in your application’s configuration and code, not in the host’s PHP package, and the host won’t touch them (they can’t, really, because they don’t know your app).
What PHP2Shell actually is
On October 21, 2026, the PHP project released 8.2.35, 8.3.36, 8.4.27 and 8.5.12 to fix two bugs rated Critical, with a CVSS (Common Vulnerability Scoring System) v4.0 score of 9.2. Both allow remote code execution, which means an attacker can make your server run their commands.
The first, CVE-2026-109618, is about running out of memory at a bad moment. If PHP hits its memory limit while it’s still setting up a request, it leaves half-built data behind, and the shutdown code later trusts that data. On Apache mod_php this all happens before your application code runs at all.
The second, CVE-2026-109619, is about state leaking between requests. Something from one request survives on the worker after its memory is freed, and the next request on that same worker uses it. That second request can be triggered by something as mundane as a PHP warning from a deprecated setting.
The timing made this worse than usual. According to Sansec’s timeline, details leaked on October 20, and Cloudflare saw early attacks the next morning, hours before the fixed versions were out. The vulnerable code goes back to PHP 5.4.0, released in 2012, so nearly every PHP site you’ve ever worked on was in scope.
Why your framework update won’t fix it
This is the part clients get wrong, and honestly some developers too. The bugs are in the PHP engine. PrestaShop, Magento and Laravel all run on top of that engine, so a composer update or a new module version changes nothing here. Sansec put it plainly for eCommerce: Magento stores are affected even when their own code is clean.
As of today, we haven’t found an advisory from PrestaShop, Adobe or the Laravel team about these CVEs. So the stack-specific notes further down are our own practitioner guidance, not quotes from the vendors. If that changes, we’ll update this post and say so.
The host patches PHP. Your team owns the configuration and code paths that decide how easy the next bug in this family will be to exploit.
The app-side checklist, step by step
These steps assume you have SSH (Secure Shell, the remote terminal) access to the server or at least to the site’s files. Paths in uppercase are placeholders. Replace SITE_ROOT with your site’s document root, for example /home/USER/public_html on cPanel hosting.
Step 1: Confirm the patched PHP is really running
The version number alone can mislead you. cPanel backported the fix into older branches (ea-php74 through ea-php81), so a server that still reports PHP 8.1 may already be patched. Upstream PHP has no fix for 8.1 and older, which is why the changelog matters more than the number. On a cPanel server running RHEL or AlmaLinux, run this, replacing php81 with the version the site uses:
|
1 |
rpm -q --changelog ea-php81-php-cli | grep -m1 CVE-2026-109618 |
If it prints a changelog line that mentions CVE-2026-109618, that PHP build has the fix. If it prints nothing, the build isn’t patched yet. For PHP older than 7.4, cPanel points to TuxCare ELS (Extended Lifecycle Support), a paid service that keeps backporting security fixes.
Step 2: Find out which SAPI serves the site
The SAPI (Server API) is the way PHP connects to the web server, and it changes your risk a lot. Apache mod_php is the worst case, because both bugs were proven against it with default settings. PHP-FPM (FastCGI Process Manager) is harder to attack, but one confirmed attack path works against it too, so don’t treat it as safe. Create a temporary file in the site root with this content:
|
1 |
<?php echo PHP_VERSION . ' ' . PHP_SAPI; |
Open it in a browser. You’ll see something like 8.3.36 fpm-fcgi or 8.1.34 apache2handler. The second word is the SAPI, and apache2handler means mod_php. Use a random file name, and delete the file the moment you’ve read it.
The command line can report a different PHP from the one serving web requests, which is why this check goes through the browser and not php -v. (On shared hosts, those two disagree more often than you’d think.)
Step 3: Clean up per-directory PHP settings
This is the step only your team can do, and it’s the one I’d put first if I could only pick one. On mod_php, any php_value or php_flag line in an .htaccess file is applied before the request starts. If that value is deprecated or invalid, PHP raises a warning at that early stage, and the second bug uses exactly that kind of early warning. Hiding the warning doesn’t help, because the advisory says the damage happens before PHP decides whether to display or log it. List every such line in the site:
|
1 |
grep -rn --include=.htaccess -E "php_(value|flag|admin_value|admin_flag)" SITE_ROOT |
Remove the obsolete ones and move the rest into php.ini or the FPM pool configuration. The advisory names these as typical offenders:
- The mbstring encoding settings
mbstring.internal_encoding,mbstring.http_inputandmbstring.http_outputare a problem whenever they’re set explicitly. - The iconv settings
iconv.input_encoding,iconv.output_encodingandiconv.internal_encodingare a problem in the same way. - The setting
auto_detect_line_endings=1raises a deprecation warning on current PHP. - Malformed values such as a
memory_limitwritten with a typo raise warnings on PHP 8.2 and later.
On nginx with PHP-FPM, the same risk applies when the server passes PHP_VALUE or PHP_ADMIN_VALUE to PHP. Check the nginx configuration too:
|
1 |
grep -rn -E "PHP_VALUE|PHP_ADMIN_VALUE" /etc/nginx/ |
Step 4: Turn off session upload progress
Session upload progress is a PHP feature that reports how far a file upload has got. It’s on by default, almost nothing uses it, and it’s the path behind one of the confirmed attacks on both mod_php and FPM. PHP’s own advisory suggests keeping it off even after you patch, because attackers will keep poking at it. Check whether your code uses it first:
|
1 |
grep -rn "upload_progress" SITE_ROOT --include=*.php |
If that finds nothing outside vendor libraries, add this line to php.ini or the FPM pool configuration:
|
1 |
session.upload_progress.enabled = 0 |
Restart PHP so every worker picks it up. On a typical Ubuntu server with PHP 8.3, the command is below; on cPanel, restart PHP-FPM from WHM instead.
|
1 |
sudo systemctl restart php8.3-fpm |
Step 5: Hunt the fatal errors an attacker can trigger
The second bug needs a request to die halfway through something, and a fatal error is how that happens. Out-of-memory is the obvious one, but the advisory also counts uncaught errors, failed require calls and “Maximum execution time exceeded.” It specifically asks teams to look at upload, import, error page, shutdown, destructor, serialization and extension paths, not just the pages you browse every day. Pull the most frequent fatals from the PHP error log:
|
1 |
grep -oE "PHP Fatal error: .{0,120}" SITE_ROOT/error_log | sort | uniq -c | sort -rn | head -30 |
Any fatal that an outside visitor can cause on purpose (a huge CSV import, an oversized image, a malformed upload) is worth fixing now, patch or no patch. A clean log isn’t proof, though. Old logs often skipped deprecation notices, and a log only covers the routes people actually hit.
Step 6: Stop oversized requests before PHP sees them
The first bug’s memory exhaustion tricks rely on multipart requests (the format forms use to send files) that look small but expand inside PHP. Keep post_max_size conservative, lower max_input_nesting_level, and set sensible caps on max_input_vars and max_file_uploads. Better still, if a route never accepts file uploads, refuse multipart requests at the web server. On nginx, for a JSON-only API path:
|
1 2 3 4 5 6 |
location /api/ { if ($http_content_type ~* "multipart/form-data") { return 415; } try_files $uri $uri/ /index.php?$query_string; } |
On Apache 2.4, the same rule looks like this in the virtual host or the root .htaccess:
|
1 2 3 |
<If "%{REQUEST_URI} =~ m#^/api/# && %{HTTP:Content-Type} =~ /multipart\/form-data/i"> Require all denied </If> |
After the change, send a test upload to that route. You should get a 415 or 403 response, and your normal JSON requests should still work.
Step 7: Check for signs of compromise
Exploitation started before the patch existed, and watchTowr lists both CVEs as exploited in the wild. So check, even if your host patched on day one. Start with PHP files that changed since the leak:
|
1 |
find SITE_ROOT -name "*.php" -type f -newermt "2026-10-20" |
Your own deployments will show up here too, so compare the list against your Git history. Anything you can’t explain, especially in upload folders or cache folders, needs a closer look. Then search the access logs for the public scanner, which Imunify360 reports sends a User-Agent starting with php2shell-:
|
1 |
grep -i "php2shell-" /var/log/apache2/access.log |
A hit means someone scanned you, not that they got in. Also check the admin user list in your store or app for accounts nobody remembers creating. A clean result is reassuring, but I wouldn’t call it proof, and I don’t think anyone honest would.
PrestaShop notes
A lot of PrestaShop stores live on shared cPanel hosting under Apache, which often means mod_php or LiteSpeed’s LSAPI. Those are the more exposed setups, so Steps 2 and 3 matter more here than anywhere else.
Old 1.6 and 1.7 stores tend to carry php_value lines in .htaccess that someone added years ago to make an old module work, and nobody’s looked at them since. Those are exactly what Step 3 is hunting for. The product CSV import and the module upload screen are the places where a big upload can push PHP into memory exhaustion, so put them at the top of your Step 5 list.
The back office needs a high max_input_vars for product and module forms, and that’s fine. Just don’t loosen every other input limit to match it; let the request size limits in Step 6 do their job on the storefront.
And the uncomfortable one: PrestaShop 1.6 stores frequently still run PHP 7.x. Those stores are now relying on a host backport or TuxCare to be patched at all. If that’s you, this is the week to put the upgrade on the calendar, and our PrestaShop development team can plan it with you. If you’re already on 9.x, our post on what changed in PrestaShop 9.x covers the newer architecture.
Magento notes
Magento (Adobe Commerce) stores tend to run with a very high memory_limit, often 2G or more, and it’s a common assumption that this protects them. It doesn’t. The attack works by pushing a request into whatever finite limit is set. A higher limit makes the attacker work a bit harder; it doesn’t remove the condition. PHP’s own temporary workaround is to remove the limit entirely (more on why that’s a bad idea below), which tells you the limit’s size isn’t the point.
Catalog and customer CSV imports, and the admin’s upload paths, belong in Step 5. Stores on older releases have a version problem as well. According to Adobe’s system requirements, the 2.4.4 and 2.4.5 lines were tested on PHP 8.1 only, and PHP 8.1 gets no upstream fix. Those stores depend on the host’s backported build. Our Magento maintenance team can check that for you if you’re not sure which build you’re on.
Laravel and custom PHP notes
Laravel apps that ship as Docker images have a trap of their own. Your host’s PHP update does nothing for a container. Any image built from a php:8.x base before October 21 still has the vulnerable PHP inside it until you rebuild with a fresh base. The "php" line in composer.json doesn’t protect you either; it only checks the version number. Rebuild and pull the new base image explicitly:
|
1 |
docker build --pull --no-cache -t IMAGE_NAME . |
Then run Step 2 against the running container to confirm the new version is live. If you use FrankenPHP, note that PHP’s advisory says it likely behaves like mod_php here, so treat it as the higher-risk case. We wrote about FrankenPHP for modern PHP development last year, and this is the first time that choice has carried a security footnote.
JSON-only Laravel APIs are the easiest win in this whole post: block multipart on the API routes (Step 6) and you’ve closed off the request type both bugs lean on. Laravel Excel imports and image processing are the usual memory hogs, so they go on the Step 5 list. If your app is a version or two behind, our Laravel 12 upgrade guide is a reasonable next read, and our Laravel developers can take that work on.
Custom PHP apps, the ones built in-house ten years ago and kept alive since, are where I’d expect the most trouble. They’re the most likely to have stale .htaccess directives and the least likely to have any upload limits at all. If one of them has a custom upload progress bar, that’s the one legitimate user of the feature in Step 4, so test it before you switch the setting off.
If your host hasn’t patched yet
Push the host first. While you wait, PHP’s advisories list a few temporary settings. None of them is a complete fix, and the advisories say so plainly.
|
1 2 |
session.upload_progress.enabled = 0 fatal_error_backtraces = 0 |
The second line only exists on PHP 8.5, where it removes the producer behind the strongest confirmed exploit. The advisory also lists memory_limit = -1 as the main stopgap for the first bug, but I’d only use it for a day or two on a server you’re watching closely. It lets a single request eat all the memory on the box, which trades one problem for a different outage. Restart every PHP worker after any change, or the old settings keep running.
Who owns what
| Task | Who owns it | Where it applies |
|---|---|---|
| The host installs the patched PHP build. | The host owns this task. | It applies to every stack. |
| The team confirms the patch from the changelog, not the version number. | The dev team owns this task. | It matters most on PHP 8.1 and older. |
| The team rebuilds container images on a patched base. | The dev team owns this task. | It applies to Dockerized Laravel and custom apps. |
| The team removes stale php_value and PHP_VALUE overrides. | The dev team owns this task. | It matters most for PrestaShop and legacy custom apps on Apache. |
| The team turns off session upload progress. | The host and the dev team share this task. | It applies to every stack. |
| The team fixes fatal errors in import and upload paths. | The dev team owns this task. | It matters most for Magento, PrestaShop and Laravel imports. |
| The team blocks multipart requests on routes that don’t need them. | The dev team owns this task. | It matters most for Laravel APIs. |
| The team checks files, admin users and logs for compromise. | The dev team owns this task. | It applies to every stack. |
The short checklist
- The package changelog on every server shows CVE-2026-109618.
- Every Docker image has been rebuilt on a PHP base released after October 21.
- You know whether each site runs mod_php, FPM, LSAPI or FrankenPHP.
- No .htaccess file or nginx config sets a deprecated or invalid PHP value.
- Session upload progress is off, and PHP has been restarted.
- The top fatal errors in the error log have been reviewed and fixed.
- Routes that never take uploads now refuse multipart requests.
- New PHP files since October 20 match your deployment history.
- The admin user list holds no accounts nobody can explain.
The same list, with the commands, is in the printable PHP2Shell checklist (PDF).
FAQ
Does updating PrestaShop, Magento or Laravel fix PHP2Shell?
No. The bugs are in the PHP engine itself, so only a patched PHP build fixes them. Framework and module updates don’t change PHP.
My host says the server still runs PHP 8.1. Am I vulnerable?
It depends on the build. Upstream PHP has no fix for 8.1, but cPanel shipped backported builds that keep the old version number. Check the package changelog for CVE-2026-109618, as shown in Step 1.
Is PHP-FPM safe from PHP2Shell?
No. FPM is harder to attack than Apache mod_php, but PHP confirmed one attack path against FPM through session upload progress. Patch FPM servers with the same urgency.
Do I need session upload progress?
Almost certainly not. Very few applications use it. Turn it off with session.upload_progress.enabled = 0 unless you have a custom upload progress bar that depends on it.
Will a high memory_limit protect my Magento store?
No. The attack drives a request into whatever finite memory limit is set. A higher limit raises the effort a little, but it doesn’t remove the condition.
How do I know if my site was already attacked?
Look for PHP files changed since October 20 that your deployments don’t explain, unexpected admin users, and php2shell- User-Agents in the access logs. A clean result is reassuring, but it isn’t proof.
Where this leaves you
If you take one thing from this: the host’s patch closes these two bugs, and your team’s cleanup makes the next one in this family harder to use. I’d expect more of them, because researchers now know exactly where to look, and the leak showed how fast attackers move once details are out. That’s not a prediction I can back with a number. It’s just how the last few PHP-wide incidents have gone.
We’ll update this post as PrestaShop, Adobe or the Laravel team publish anything. If you’ve seen something in your own logs that belongs here, tell us and we’ll add it with credit.
Want a second pair of eyes on your PHP2Shell cleanup?
We check the app-side items your host doesn’t touch, on PrestaShop, Magento, Laravel and custom PHP sites, and tell you plainly what we found.
Related Posts
-
August 10, 2023
Mastering Microservices in PHP: A Comprehensive Guide for PHP Developers
As a PHP developer, you might have heard about the microservices architectural style and wondered how it could benefit your projects. In this blog, we will discuss why you should consider learning microservices and how to implement Microservices in PHP in your PHP projects, using a real-world example of an
PHP Programming, Web Development, Web Development, web programming, Welcome0 comments -
July 10, 2017
4 CSS Preprocessors for Your Web Development
4 CSS Preprocessors for Your Web Development A big advantage of a CSS pre-processor is the value you can add to your client during the web development project. : Sass As a mature, highly stable, dynamic, and powerful CSS extension, Sass plays a significant role in web development projects. You


