Grok Is Killing Cursor
Since SpaceX bought Cursor in August, it has been pushing Grok on every Cursor user, and I think that is slowly killing…
Details of two critical PHP vulnerabilities, CVE-2026-109618 and CVE-2026-109619, leaked on 20 October 2026, before PHP had released a fix. PHP's security team rates both at 9.2 out of 10 on the CVSS v4.0 severity scale. The patched versions are scheduled for Wednesday, 21 October 2026 at 14:00 UTC, which is 16:00 in Berlin and 10:00 in New York. PHP's plan was to publish the details, the affected versions and the fixed versions together with that release. Now the leak is out while the patch is still hours away, and Sansec expects mass attacks within 15 minutes of the release. If you run PHP websites or servers, use the time before 14:00 UTC to find every PHP host, put stopgaps in place and prepare the update.
As of 04:53 UTC, 21 October 2026, PHP has not released the fix. The newest builds on php.net are still 8.5.11, 8.4.26, 8.3.35 and 8.2.34 from 24 September 2026, and at 04:25 UTC neither CVE had a published record at CVE.org or NVD. Until PHP publishes its advisory, any list of affected or fixed versions is unofficial.
According to Sansec, the first post about the leak appeared on Hacker News at 15:20 UTC on 20 October. At 16:39 UTC, security researcher Kevin Beaumont wrote that "Somebody has leaked CVE-2026-109618 and CVE-2026-109619 in PHP before the patch is out." PHP's announcement on its php.announce mailing list followed at 19:33 UTC. In it, Jakub Zelenka wrote for the PHP security team that both vulnerabilities are critical and that the release is set for 14:00 UTC on 21 October. He added that the team may release earlier if details become public or if it sees evidence of active exploitation. The news post on php.net adds that "Full details, affected versions, and the fixed versions will be published with the release."
From what has been reported, the flaws are in how PHP processes file-upload requests. When a browser sends a form that contains a file, it uses a multipart/form-data request, which is a request body split into separate parts for each field and file. PHP reads and splits that body itself before your application code runs. The leaked details reportedly involve PHP's session upload-progress feature, which records how far a file upload has got and stores that in the user's session. PHP has not confirmed any of this.
watchTowr told BleepingComputer that both are remote code execution flaws, which means an attacker could run their own code on the server, and that it believes they affect PHP 5, 6, 7 and 8. watchTowr also said the details leaked before a planned embargo date, the date until which they were meant to stay private, and that it believes it has reproduced CVE-2026-109618. watchTowr and a since-deleted Hacker News post called the flaws CVSS 10.0, while PHP's official rating is 9.2. Sansec calls the issue PHP2Shell, after an exploit tool shown in a leaked screenshot.
No vendor has confirmed attacks so far. watchTowr told BleepingComputer it had not seen exploitation in the wild, and its FAQ says "As of October 21, 2026, no exploitation in the wild has been reported." Huntress had not seen in-the-wild exploitation in its partner environments and had not reproduced the issue. Posts on Hacker News and X claim that exploit code is public and that attacks have started. Neither PHP nor these vendors had confirmed those claims as of their own posts.
PHP hasn't said yet, and watchTowr's FAQ lists both the affected versions and the fixes as "to be confirmed". CERT-EU's advisory says the flaws could affect all PHP versions from PHP 5 onward, citing a public post, and that no technical details are public. CERT-EU tells organizations to prepare for immediate patching. Where that isn't feasible, it suggests isolating internet-facing applications from public networks until a fix is available.
PHP currently supports the 8.2, 8.3, 8.4 and 8.5 branches, according to its supported versions page, and security support for 8.2 ends on 31 December 2026. PHP 8.1 and older are end of life. I don't expect an official fix for them, and Sansec says servers on 8.1 or older get none.
If the reports are right, the bugs sit in code that PHP runs before Laravel, WordPress or any other application code sees the request, so having no upload form doesn't make a site safe. Sansec makes the same point for online stores, writing that the fix has to happen at the infrastructure level, not in store code.
Huntress recommends starting with an inventory of every PHP install, including PHP that comes inside vendor software, then patching internet-facing systems first and isolating PHP versions that are end of life. For each host, write down which PHP branches are installed, where PHP came from and whether the host can be reached from the internet. Where PHP came from decides where your fix will come from. That could be your distribution's own packages, Ondřej Surý's PPA (a third-party package archive for Ubuntu) or packages.sury.org, an official Docker image, a hosting panel or a managed host.
Include staging servers, old marketing sites, admin tools on subdomains and servers with several PHP versions installed side by side. On Debian and Ubuntu, ls /etc/php shows the installed branches.
Two changes reduce the risk until the fixed versions are out. They were checked against PHP's source code and the PHP manual, but they are not an official PHP mitigation. When someone suggested that turning off session upload progress might be enough, PHP core developer Gina Peter Banyard replied, "The only thing I can say is that the only mitigation is patching / upgrading PHP. I sadly know too much." Use the stopgaps to lower the risk for a few hours, and update PHP as soon as the fixed builds exist.
The leaked details point at the upload-progress feature, which is on by default. You turn it off with session.upload_progress.enabled in php.ini.
session.upload_progress.enabled = Off
If you run PHP-FPM, the process manager that runs PHP behind nginx or Apache, also lock the setting with php_admin_flag in every pool configuration. Otherwise it can be changed per directory, for example in a .user.ini file. On Debian and Ubuntu the pool files live in /etc/php/8.3/fpm/pool.d/, with your branch in place of 8.3.
php_admin_flag[session.upload_progress.enabled] = off
Then restart PHP-FPM for each branch, for example with sudo systemctl restart php8.3-fpm. The only visible change is that upload progress bars built on this PHP feature stop working. The person behind the leak claims a second route through PHP's multipart handling that this setting does not cover. Nobody outside PHP's security team can settle that before the advisory, so add the web server block as well.
The stronger stopgap is to refuse every request whose Content-Type header contains "multipart" before it reaches PHP. Block it for all HTTP methods and not only POST, because PHP 8.4 added request_parse_body(), which parses multipart bodies for other methods as well. Put the block into every nginx server block or Apache virtual host that passes requests to PHP, including default and catch-all servers, because attackers can send requests straight to your server's IP address.
For nginx, add a map in the http context. On Debian and Ubuntu a new file in /etc/nginx/conf.d/ is loaded there.
map $http_content_type $block_multipart {
default 0;
"~*multipart" 1;
}
Then add this guard at the top of each server block that passes requests to PHP.
if ($block_multipart) {
return 403;
}
If the server has an error_page rule that sends 403 errors to PHP, the blocked request would still end up in PHP. Use return 444; there, which makes nginx close the connection without an answer. Run sudo nginx -t, reload nginx and then check with sudo nginx -T that the guard is in the loaded configuration. On newer Laravel Forge sites the include folders under /etc/nginx/forge-conf/ use the numeric site ID, so a file in a folder named after the domain is not loaded.
For Apache 2.4, put this block above the WordPress rules in .htaccess, or into the virtual host configuration.
<If "req('Content-Type') =~ /multipart/i">
Require all denied
</If>
Keep req('Content-Type') as shown and don't swap in %{CONTENT_TYPE}. In Apache expressions that variable holds the content type of the response, so a block written with it lets multipart requests through. If Apache answers with a 500 error after the change, the server doesn't allow these directives in .htaccess, and the block has to go into the virtual host instead.
You can test the block from outside with curl. This request should get a 403, or 000 if you used return 444;.
curl -s -o /dev/null -w '%{http_code}\n' -F test=1 https://example.com/
Run the same request again with --resolve example.com:443:203.0.113.10, using your server's real IP address, to check that a request that skips your CDN is blocked as well.
The side effect is that file uploads stop working until you remove the block after patching. That includes WordPress media uploads, contact forms with attachments and upload fields in Laravel apps. Normal pages, logins, JSON APIs and forms without file fields keep working. Some form plugins and JavaScript FormData requests send multipart even when there is no file, so test the forms that matter to you after the change.
If you can afford it, take staging sites and PHP apps you don't need today offline at the web server until they are patched. Gina Peter Banyard wrote that turning a server off for a day might be the most sensible thing if you can afford it, but that it is "far from a reasonable thing to demand for most people".
Laravel maintenance mode, WordPress security plugins, application middleware and login checks all run after PHP has already processed the request body, so they don't stop this. Setting file_uploads = Off doesn't help either, because PHP still processes the multipart body and only skips the file parts. Small upload size limits give you no safe threshold, and a value of 0 in post_max_size means no limit at all. Turning off enable_post_data_reading breaks normal forms and doesn't cover the explicit parsing that PHP 8.4 added.
A web application firewall (WAF) in front of your site, like Cloudflare, only helps if your own server can't be reached directly. Cloudflare published emergency WAF releases on 21 October for its Managed Ruleset and Free Ruleset, with rules named Generic Rules - Anomalous Execution. The entry names no CVE and doesn't mention PHP. The timing suggests a connection, but that is my inference and Cloudflare doesn't say so. Any request that goes to your server's IP address skips the WAF, so the web server block belongs on the server itself.
Because PHP may release before 14:00 UTC, keep an eye on php.net and the php.announce list. Start with PHP's official advisory and note the fixed version for each branch. Then work through your inventory, internet-facing hosts first.
Before you press update, check that your package source already offers the fixed build. apt-cache policy php8.3-fpm shows the installed version and the candidate version from your configured repositories. A hosting panel's PHP "Update" button installs whatever the configured repository offers, which may still be the old build. Distributions like Debian backport security fixes instead of moving to a new upstream version, so a patched distribution package can still show an old-looking version number. For those packages, check the changelog with apt changelog php8.3-fpm or compare the exact package version with the distribution's advisory. Update every installed PHP branch, not only the one the php command points to.
Restart PHP-FPM for each branch. After that, restart long-running PHP processes like queue workers, Horizon, Reverb, schedulers and Octane, because they keep running the old PHP binary until they restart. Check the running version privately, for example with php-fpm8.3 -v and the start time in systemctl status php8.3-fpm, and not through a public phpinfo page.
The official php Docker image builds PHP from the php.net sources, so a patched image shows the new upstream version, and your existing images stay unpatched until you rebuild them. Pull the patched base image, rebuild and redeploy. docker run --rm your-image php -v shows which PHP version an image contains. Laravel Vapor runtimes need the same rebuild and redeploy.
On shared and managed hosting your host has to patch PHP. Ask the host to confirm that the fixed build is installed, and move any site still on PHP 8.1 or older. Servers on 8.1 and older keep the stopgaps, or stay isolated, until they are upgraded.
Ubuntu 20.04 reached the end of standard support on 31 May 2025, and Ubuntu Pro extends its security maintenance to 2030. If you run PHP from Ondřej Surý's PPA on 20.04, there is nothing to update to. The PPA publishes php8.2 to php8.5 only for Ubuntu 22.04 and 24.04, and packages.sury.org, which the PPA is being merged into, has no 20.04 builds either. Nobody has said yet whether Canonical will ship fixes for these CVEs on 20.04. A new 22.04 or 24.04 server is the controlled way out, and the stopgaps stay in place until you've moved.
Once you have patched, check whether anyone got in before the patch. Look back to about 15:00 UTC on 20 October, shortly before the first public leak post at 15:20 UTC.
find /var/www -type f -newermt '2026-10-20 15:00 UTC' lists files changed since then, along with a lot of noise from caches and logs..user.ini files and the auto_prepend_file setting for changes.Huntress also suggests looking for web shells and alerting on PHP worker processes that start shells or download tools. A clean result doesn't prove the server is safe. If you do find something, isolate the server and keep the web server and PHP logs. When the evidence points to a break-in, rebuild the server and rotate every secret the PHP user could read, including .env files, database passwords, API keys and app keys.
Update, 21 October 2026, 05:35 UTC. I put both stopgaps on the servers I manage this morning, and since publishing I tested the block on more web servers. Some points above need a correction, and there are a few more places to check before the patch. PHP still hasn't released the fix. The newest builds on php.net are still 8.5.11, 8.4.26, 8.3.35 and 8.2.34.
In the curl test, a 000 doesn't prove that nginx closed the connection with return 444;. curl shows 000 for any connection that fails, so check the nginx access log for the request. Use -sS instead of -s, so curl prints the error. Then send the same request as a PUT to a PHP file, because PHP 8.4 can also parse multipart bodies on other methods.
curl -sS -o /dev/null -w '%{http_code}\n' -X PUT -F test=1 https://example.com/index.php
sudo nginx -T prints the configuration files on disk, not the configuration nginx is running. The curl test is what shows that the block is active.
I wrote that forms without file fields keep working. That's not true for all of them. Contact Form 7 sends its normal submissions as multipart even when the form has no file field, so those forms stop working while the block is in place. In Laravel apps, Livewire and Filament uploads that go through your server also stop working.
php-fpm8.3 -v shows the version of the installed binary, not of the running service. The start time in systemctl status php8.3-fpm tells you whether the service started after the update. If PHP runs as an Apache module, restart Apache instead of PHP-FPM. FrankenPHP has PHP built into its binary or image, so you need a new FrankenPHP build, not new PHP packages.
Run sudo apt update before apt-cache policy. Otherwise it shows the old package lists.
On Laravel Vapor, a new base image and a redeploy only help with Docker runtimes. Native runtimes come from Vapor, so wait for Vapor's fixed runtime and then redeploy.
A WAF like Cloudflare still filters the requests that go through it when your server can be reached directly. Requests sent straight to your server's IP address skip it, so you also need the block on the server.
There was never a PHP 6 release, so read watchTowr's "PHP 5, 6, 7 and 8" as PHP 5 and later. And when I wrote that no vendor has confirmed attacks, I meant the vendors cited here, in their posts at that time.
Before you patch, copy the web server and PHP logs since 20 October somewhere safe. You need them for the compromise check, and deploys or log rotation can remove them.
I tested these in containers. With the snippets below, multipart requests got a 403 on POST, PUT and PATCH.
For Caddy and FrankenPHP, use this matcher and response.
@multipart header_regexp Content-Type (?i)multipart
respond @multipart 403
Where you put it matters. If your site block has no route or handle block, add both lines at the top of the site block. If PHP sits inside a route or handle block, like in Laravel Octane's Caddyfile, put the respond line at the top of that block. Caddy runs those blocks before a respond outside them. When I tested FrankenPHP with the line outside the route, PHP still got the multipart requests.
LiteSpeed reads rewrite rules from .htaccess. On LiteSpeed hosting, put this above your other rewrite rules and outside the # BEGIN WordPress block.
RewriteEngine On
RewriteCond %{HTTP:Content-Type} multipart [NC]
RewriteRule ^ - [F]
In my test, OpenLiteSpeed only used the .htaccess change after a restart, so restart it and test again. On Apache, stay with the <If> block from above. I tried this rewrite version on Apache, and a subfolder with its own .htaccess containing RewriteEngine On let multipart requests through to the PHP files in that folder.
If HAProxy handles HTTP in front of your PHP servers, add this line to the frontend, above any rules that allow or answer requests. It can't see the header when HAProxy passes TLS through without decrypting it.
http-request deny if { req.hdr(content-type) -m sub -i multipart }
If your site goes through Cloudflare's proxy, you can also block multipart there. Free plans include five custom rules. Create one with the action Block and this expression.
any(lower(http.request.headers["content-type"][*])[*] contains "multipart")
It only applies to hostnames that go through the proxy, and an IP Access Allow rule skips it. I haven't tried it in a live zone, so send the curl test to your domain and check under Security Events that the rule blocked it. You should also keep the block on the server. One way to close the direct route to your server is a firewall that allows ports 80 and 443 only from Cloudflare's IP ranges, for IPv4 and IPv6. Check first that nothing on that server is reached without Cloudflare.
Go through all server blocks in sudo nginx -T and look for fastcgi_pass or a proxy_pass to PHP. When I did this on my servers, two sites I thought were static still had a PHP handler, and one server ran PHP for requests sent to its bare IP address.
Also check for PHP servers that can be reached without going through your web server, like PHP's built-in server or Laravel Octane on a public port. sudo ss -tlnp lists the ports programs listen on. Docker containers with published ports need their own check, because Docker's port rules can skip a UFW firewall. Requests that skip nginx also skip its block.
If you can't take an admin tool like phpMyAdmin or a staging site offline, allow only your own IP address with allow and deny all; in its nginx server block. A location block with its own allow or deny lines replaces them. Behind Cloudflare, nginx sees Cloudflare's addresses, so check that your address gets through and another one gets a 403.
With cPanel, Plesk or CloudLinux, a site can run on one of several PHP installs. Switching a site to another version doesn't tell you whether that build is fixed. Ask your host for the exact patched build that serves each domain.
A Laravel 419 response to your test request doesn't mean you're safe. With a normal multipart POST, PHP has parsed the body before Laravel's CSRF check runs. Disabling system() and other functions with disable_functions doesn't fix these bugs either, because PHP still parses the multipart request.
Once the fixed version serves the site, remove the multipart block from the web server and from Cloudflare or any other proxy. Then test a file upload and the forms that broke. You can leave upload progress off unless something you run needs it.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com