The Daily Commit · Section Edition Front Page PHP AI Dev EN DE FR ES

The Php Times

The Editorial — Ecosystem

After php2shell, your web user should be the dullest account on the box


The php2shell exploits leave nothing in your logs.

November 5, 2026 An editorial by Kai

You only see what the attacker does next, which means detection depends on www-data almost never doing anything interesting. That's a design choice we can make right now. Sometimes it costs us convenience, sometimes WordPress auto-updates, but it beats grepping process lists every 60 seconds and hoping you sampled at the right moment.

"sh -c /usr/sbin/sendmail -t -i", owner www-data. I found that line in a process listing last week and spent a good four minutes with my pulse up before I remembered that PHP's mail() does exactly this, every single time, by design. That false alarm is the whole column, really. Since October 21 we've all been patching CVE-2026-109618 and CVE-2026-109619, the pair everyone now calls php2shell, and the community write-ups on detecting them keep running into the same wall: the exploit itself is a memory bug that fires before your application code runs, so your logs show nothing. All you can catch is what comes after. And what comes after only stands out if your web user is normally boring.

So my argument is about architecture, not alert rules. If www-data regularly spawns shells, writes .php files into the document root and runs cron jobs, then no detection rule anyone writes will tell an attacker apart from your Tuesday. Rules can only be as sharp as your baseline is quiet. A web user that never executes anything and never writes code gives you a signal you can actually believe. A web user that does both whenever a plugin feels like it gives you a dashboard full of level 8 alerts that everyone learns to ignore by Thursday.

Remember how bad this one is. CVSS v4.0 9.2, unauthenticated, and it hits PHP-FPM, mod_php, php-cgi, FrankenPHP and LiteSpeed alike, with mod_php the worst case because the attacker is in before your router ever loads. Fixed builds are 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Anything on 8.1 or older has no official fix, and Debian bullseye users stuck on PHP 7.4 got nothing either. When the advisory dropped, the Wazuh vulnerability feed didn't know about either CVE yet, CISA KEV hadn't listed them, and the only proof of concept going around was unverified and possibly booby-trapped. For a few days, plenty of teams were defending against something their scanners couldn't even name.

The strongest objection deserves a straight answer, because it's correct. Real PHP applications do these things on purpose. WordPress updates itself by writing PHP into its own tree. Half the CMSes I've maintained run scheduled jobs as the web user because that was the path of least resistance in 2014. mail() shells out. Telling a small agency with forty client sites to rebuild all of that during an emergency is a fantasy, and I won't pretend otherwise. The detection-first crowd has a point too: you can't redesign under fire, so you watch what you have and accept the noise.

I still land on the other side, and here's the reason. Every one of those habits is something you can drop for a known, finite price. Send mail over SMTP with a library and mail() never forks again. Run updates from a deploy user through your pipeline, and make the document root read-only for the process that serves it. Move cron to its own account. None of this is exotic, and once it's done, a sampled process list or a file integrity watcher flips from a noisy hint to a near-certain alarm. A 60-second polling sample will always miss a curl that lives for two seconds. On a quiet account, though, even one hit is enough, because nothing should be there at all.

One more thing that has nothing to do with clever detection: a patched package doesn't patch the php-fpm workers that are already running. I've seen two servers this month on 8.3.36 according to apt and still on the vulnerable binary according to reality, because nobody restarted the pool. That's the most PHP failure mode imaginable, honestly, our shared-nothing model forgiving almost everything except the master process that's been up since August. Restart it. Then go and check that you actually did.

For the 7.4 to 8.1 stragglers, the honest move is to take them off the public internet, not to build monitoring around them and call it coverage. Watching a door you know you can't lock is useful for a week, at best. Past that it's a plan to find out about the compromise a bit sooner.

So here's what I'd genuinely like to hear from you, because I suspect the answers split along agency and product lines: on your production boxes today, can the user that serves PHP write to the directory it serves from? And if it can, what's the one feature you'd lose by taking that away, and is that feature worth a php2shell-sized blind spot?

Rate this article: 0

Readers’ Forum

No contributions yet — open the debate.

← Ecosystem — Page B1

"All the Code That's Fit to Ship" · The Daily Commit · Screen edition · Imprint · Privacy Policy