VicroCode
Make Code Create Value
VicroCode is a lightweight online platform for publishing, running, sharing, and monetizing code projects. Launch HTML, Python, SQLite, AI agents, management tools, games, and more without server setup.
Please wait while VicroCode loads. You can also explore the AI programming guide
Loading...

AI MARKET GUIDE

Own the Advisory Data: Building a PHP CVE Lookup Instead of Chasing a Remote Scanner

When PHP2Shell broke, everyone grabbed scanners that probe servers. The durable build is quieter: a version-to-patch ledger you control, a lookup endpoint, and a board you can read at a glance.

The night the PHP2Shell advisory landed, the reaction was predictable. CVE-2026-109618 and CVE-2026-109619 got tagged as serious remote code execution bugs, ops teams stopped sleeping, and within hours people were passing around links to online checkers and a `php2shell-checker` repo. One Japanese politician even tweeted about updating PHP, which tells you how far the panic traveled. The reflex was the same everywhere: find a tool that pokes at a server and tells you if you're exposed.

I get the appeal. A scanner feels like action. But if you watch the actual confusion in the threads, the real pain wasn't "can something probe my box." It was "I'm on 8.2.35, am I even affected? and "why can't I see the update in my panel?

People weren't missing a scanner. They were missing a clear, trustworthy answer to a boring question: given my exact PHP version, am I vulnerable, and what's the fixed build I should be on?

That question has a durable, buildable answer. The scanner is the part you can't own and shouldn't chase. The advisory ledger is the part you can.

The signal under the noise

Strip away the memes and the panic, and the evidence shows one recurring shape: a messy, fragmented patch map that nobody had in one place.

The official PHP project shipped fixes on some branches and not others. The current builds floating around were 8.5.12, 8.4.27, 8.3.36, and 8.2.35. But PHP only published source on GitHub without packaged releases, so the older branches got picked up downstream. A control panel vendor packaged its own repaired builds for 7.4, 8.0, and 8.1, landing on 7.4.34, 8.0.27, and 8.1.35 as fix versions. The practical guidance that emerged was blunt: get to at least 7.4, because older branches had no patch at all.

Now put yourself in the shoes of the person running a handful of sites. Your version might be fixed upstream, fixed by a downstream packager, or stranded with no patch. One commenter on 8.2.35 genuinely couldn't tell if they were safe, and the answer was that 8.2.35 *was* the patched build released that same night. Another had to be told to click "refresh software list" before the update even appeared. That's not a scanning problem. That's a data problem. The fixed-version table lived in a WeChat announcement, a GitHub tag page, and a panel UI, and the human in the middle had to reconcile them under stress.

That reconciliation is the thing worth building. And it's the thing a scanner never gives you, because a scanner tells you "affected / not affected" without ever teaching you the map.

Draw the boundary honestly first

Before I describe what to build, the honest part. VicroCode can run Python and host HTML apps, but it does not run PHP, and it will not scan arbitrary remote hosts. So anything that depends on executing PHP or reaching out to touch someone else's server is simply off the table here. If your goal is "point at an IP and fingerprint its PHP," this isn't your tool, and pretending otherwise would waste your time.

That boundary is also why the advisory-data approach is the right fit rather than a consolation prize. The lookup is pure data and logic: a version string in, a verdict and a fixed build out. No PHP runtime required. No remote network probing required. It maps cleanly onto what the platform actually does, which is the only kind of mapping worth trusting.

The ledger: SQLite as the source of truth

Start with the table everyone was missing. A single SQLite database holds the advisory as structured rows rather than scattered prose. Something like a `cve` table keyed by identifier, and an `affected_versions` table that encodes, per branch, the vulnerable range and the first fixed build.

From the evidence, your seed rows write themselves. CVE-2026-109618 and CVE-2026-109619 as the two entries. Branch rows for 8.5 fixed at 8.5.12, 8.4 at 8.4.27, 8.3 at 8.3.36, 8.2 at 8.2.35, and the downstream-packaged fixes at 8.1.35, 8.0.27, and 7.4.34. A `patch_source` column to record whether a fix came from upstream or a downstream packager, because that distinction mattered to real people deciding whether to upgrade or patch in place. A note field for branches with no patch, so the lookup can say "no fix exists, you must move branches" instead of staying silent.

You can build and correct all of this directly in the SQLite editor, which matters more than it sounds. Advisories get revised. A fixed build gets superseded, a new affected branch shows up, a severity rating changes. Being able to open the table and edit a row by hand means your ledger stays accurate without a redeploy. The data is the product, so treat editing it as a first-class workflow, not an afterthought.

One caution on the data itself: only enter what you can confirm. One of the news snippets described the two CVEs as 9.2-severity bugs surfaced by an AI model, but I'd treat specific severity scores and discovery credits as unverified until you check them against the primary advisory. Your ledger is only as good as your sourcing discipline. Leave a field blank before you guess at it.

The lookup: a Python endpoint that answers one question

On top of the ledger, a small service. You can run Python online to host the logic that takes a version string, normalizes it, looks up the matching branch, and returns a structured verdict: affected or not, the first fixed build on that branch, the patch source, and a plain-language next step.

The only genuinely tricky bit is version comparison, and it's worth getting right because it's exactly where humans were tripping. "8.2.35" being the fix, not the vulnerable build, is a semantic-version comparison, not a string match. Parse major, minor, and patch, compare numerically, and handle the branch-no-longer-supported case explicitly. Expose it as a hosted API endpoint so the same logic serves both a UI and any script you want to point at it later. In-platform tool calls let an AI agent query the same endpoint, so you could wrap the whole thing in a chat-style "paste your `php -v` output, I'll tell you where you stand" helper without duplicating the rules.

Keep the endpoint read-only and the input tightly validated. It takes a version string and nothing else, so there's no reason to accept anything that isn't one. Since this answers security questions, if you ever put write access or an admin view on it, that's the moment to add authentication rather than leaving an open mutation path. The read path can stay public; anything that edits the ledger should not.

The board: HTML you can read at a glance

The last piece is the one that actually calms people down. A single-page board, which you can run HTML online, that lists each branch, its status, and its fixed build in one glance, plus a box where someone types their version and gets the verdict back from your endpoint.

This is deliberately the opposite of a scanner's output. A scanner gives a binary and moves on. The board teaches the map. Someone on 8.0 sees that their fix came from a downstream packager, not upstream, and understands why the upgrade advice was nuanced. Someone on an unpatched old branch sees red and a clear "no fix, you must move" message. The person who couldn't find the update in their panel at least knows what build they're aiming for before they go digging.

Because the board, the endpoint, and the ledger all live in one project, you can publish and share it as a unit. If you maintain it well, that's a small thing worth hosting for a team or a community rather than depending on a third-party checker whose data you can't inspect and whose uptime you don't control.

Why owning the data wins

The case against the remote checker isn't that scanners are useless. It's that they're someone else's black box answering a question you could answer better with data you can see. During the PHP2Shell scramble, a hosted checker going down, going stale, or quietly returning wrong verdicts would have been invisible to the people relying on it. An advisory ledger you built and can edit has none of that fog. You know where every row came from, you can correct it in minutes, and the verdict logic is a few lines of Python you can read.

There's a broader pattern here worth naming. A lot of the AI-era building I see is reactive: watch what's trending, spin up a tool, throw tokens at it, ship something hollow, repeat. One developer described exactly that loop and called the output what it was. The antidote isn't a cleverer prompt. It's picking the half of a problem that has a durable, ownable answer and building that. In this case the panic produced dozens of disposable scanners. The thing that lasts is the boring, correct, editable table of who's affected and what to upgrade to. Build that, and you've got something still useful the next time a branch gets patched, long after the memes have moved on.