Two critical PHP RCEs, a leaked embargo, a continent of nervous sysadmins, and one daemon that already solved the problem.
TL;DR
- PHP2Shell (CVE-2026-109618 / CVE-2026-109619, CVSS 9.2 each) hit the entire PHP world at once. Unauthenticated RCE, every PHP version since 5.4, and the embargo leaked a day early.
- Meanwhile, the Dutch NCSC, the Tweede Kamer and Tweakers pulled their sites offline, RIPE NCC took a few of its own down, and even BreachForums decided today was a good day for maintenance.
- The same day, CFM got rules 10021 and 10022, which block the multipart request shapes the advisories describe. They are merged in main.
- This is a stopgap, not a patch. Update PHP (8.2.35 / 8.3.36 / 8.4.27 / 8.5.12) and set
session.upload_progress.enabled = 0. Details on what we don’t cover are below.
The vibe on October 21st
I opened my feeds this morning and found a sysadmin Pompeii. Someone had a “block all multipart/form-data” snippet. This is a respectable strategy, in the same way that unplugging the server is a respectable strategy. Someone else was dutifully flipping an ini setting that the PHP core team itself said wasn’t a real fix. Others were checking whether their repo would even ship the update that day. Remi’s repository, for one, wasn’t going to.
I had coffee, because my production servers have a WAF in front of them and I am, by temperament, lazy.
What the exploit actually needs
Strip away the hype and both bugs share a shape: make PHP run out of memory while it is still parsing the multipart body, before a single line of your application runs. A half-initialized request, a shutdown that trusts it, and you have your shell.
That is useful to a defender, because “make PHP choke on a weird multipart body” leaves fingerprints in the body itself. So 10021 looks for the shapes the advisory describes:
| Tag | What it catches |
|---|---|
PART_HEADERS |
a single part with more than 16 header lines (a browser sends one or two) |
EMPTY_FILES |
128 or more empty-filename file controls |
NESTING |
a file field nested more than 16 levels deep, or a plain field more than 32 |
A hit means a 403 and a 6-hour ban. Rule 10022 handles multipart with no Content-Length on a body the edge never read. It ships held, with autoblock off, because some perfectly legitimate streaming clients send exactly that.
What it does not do
Same rules as always on this blog: no overselling.
- Padding beats it. The structural checks only see the first 32 KB of the body (
waf_body_max_len). An attacker who pads first walks past them. - It matches shapes, not the bug. It stops the exploit as published and its copies, not every possible variant.
The only real fix is the PHP update. This buys time and telemetry, and a WAF/CVE-2026-109618 alert if someone knocks. Guess what, I send them to tarpit.
Practical recommendation
- Update PHP. Check every handler separately: CLI, FPM and Apache module are not one package.
- Set
session.upload_progress.enabled = 0, andfatal_error_backtraces = 0on 8.5. It’s a partial mitigation, not a cure.
The takeaway isn’t “CFM beats PHP2Shell”. It’s smaller: when the person who wants the rule and the person who merges it are the same tired human, the gap between “advisory published” and “rule in main” is an afternoon. Back to the logs.