A Clean Scan Is a Data Point, Not a Verdict: Lessons from PHP2Shell Week

A Clean Scan Is a Data Point, Not a Verdict: Lessons from PHP2Shell Week

●4 ●14
calendar_today ago • schedule3 min read

PHP's two critical flaws, CVE-2026-109618 and CVE-2026-109619 (PHP2Shell), were patched in 8.5.12, 8.4.27, 8.3.36 and 8.2.35. The advice everywhere was to update. I want to write about something less covered: how much you can honestly claim afterwards.

The scan that found nothing

I ran Laravel Scalpel, an open source filesystem intrusion scanner, against three Laravel applications after updating. No backdoor files. My first instinct was relief. My second was to ask what that result actually rules out.

Why a negative result is weak evidence

A scan can only report on what it can see, and it can only recognise what it knows how to recognise. Scalpel looks at five things: PHP files in places they should not be, known obfuscation patterns, risky directives in .htaccess and .user.ini, the integrity of .env, and differences from a saved baseline. Each is a question it answers well. Anything outside them is a question it never asks. Coverage and sensitivity multiply, and if either is low, 'found nothing' tells you little.

There are at least two explanations for my result. My applications are small, which lowers the odds that anything needed to hide. Or something sits outside the questions above. A scanner inside the application also shares the web server's user, so a flaw that grants code execution in that process gives an attacker the means to tamper with the tool. I ran Scalpel from inside the application and through an external runner for that reason, which narrows the gap without closing it. My strongest evidence is not the scan but a routine that predates it: since April, a scheduled external diff against my baseline has reported to a Telegram bot. I refreshed the baseline myself after the update, so any unexpected change before that should already have alerted me, and none did. That evidence has conditions too: the runs must actually have happened in the window, and the alert level must cover what an attacker would change. Scalpel's documentation states the first limit plainly, and I would rather state all of them than have a reader discover them. From the output alone I cannot separate these cases.

A ladder of claims

It helped me to treat each check as supporting a different, specific statement:

  1. Version verified: the PHP that serves web traffic is a fixed version, containers included. Supports: 'this flaw can no longer be used against us.'
  2. Logs reviewed from 20 October: no repeated 500s or memory limit errors that look like probing. Supports: 'we saw no sign of attempts in these logs.'
  3. Filesystem scan clean: no known backdoor patterns in the application files. Supports: 'we found no evidence of intrusion in these files.'
  4. Secrets rotated: exposed credentials no longer work. Supports: 'even if memory was read, those secrets are dead.'
  5. Rebuilt from a known good image: supports the only claim close to 'clean.'

Most of us stop at rungs one to three and announce we are fine. Only the last rung justifies that word.

Why the timing makes this sharper

The identifiers leaked about a day before the fix, and a security firm reported exploitation attempts shortly after release. For teams that patched hours or days later, the unprotected window was real, and a patch does nothing about what happened inside it.

What I would write in a post-patch note

Something like: 'Updated PHP on this date. Reviewed logs from 20 October. Scanned the application filesystem. Found no evidence of intrusion in those places. Rotated these secrets.' Each sentence is a claim you can defend, and the places you did not check are visible by omission.

I would be glad to hear what steps other teams include in their own post-patch verification.

2 Comments

1 vote
1
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelski - Apr 23

MCP Is the USB-C of AI. So Why Are You Plugging Everything In?

Ken W. Algerverified - Jun 10

Cisco's Amy Chang: A Model's "Passport" Doesn't Tell You Where It Actually Came From

Tom Smithverified - Aug 27

Comparison: Universal Import vs. Plaid/Yodlee

Pocket Portfolio - Mar 12

SE Ranking Review (2026): Pros, Cons, and Verdict

floxolab - Oct 22
chevron_left
774 Points • 18 Badges
Bandung, Indonesia • github.com/hryagstn
5Posts
4Comments
4Connections
Senior IT Engineer working across DevOps, infrastructure, backend development, and security. I write... Show more

Related Jobs

View all jobs →

Commenters (This Week)

1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!