PHP2Shell: How I Found Out and What I Did About It

A late-night BBC headline about a critical PHP flaw sent me checking my own WordPress site. Here's how I found my PHP version, protected and verified my backups, checked for intruders, and pushed my host for a straight answer, plus what's still open.

A note on what’s not in this post: I’ve left out my exact PHP version and server details until my host confirms the fix is installed. Publishing those while a patch is unconfirmed would just point scanners at my site. I’ll update this post once I hear back.

How I Found Out

At 10:43 PM on Wednesday, October 21, 2026, I saw a BBC headline: websites were being taken down worldwide after AI uncovered a critical security threat. The threat was in PHP, the programming language underneath WordPress, and underneath this blog.

Governments in France and Finland had pulled web services offline. Even the BBC took pages down. That got my attention fast, because I don’t run the server this site lives on. My hosting company does.

This post is the record of what I did over the next hour and a half: what I checked, what I found, and what is still open. In keeping with how I run this blog, it is dated and in public, including the parts that aren’t resolved yet.

What PHP2Shell Is

PHP2Shell is the nickname for two flaws in the PHP engine itself: CVE-2026-109618 and CVE-2026-109619. Both are rated 9.2 (Critical) on CVSS v4.0. Either one can let an attacker who has no account run their own code on a web server.

  • CVE-2026-109618: when PHP runs out of memory partway through a request, it can clean up half-built data as if it were valid.
  • CVE-2026-109619: leftover data from one request can survive into the next request handled by the same worker, after its memory has been freed.

The flaws affect nearly every PHP version back to 5.4. Researchers at Calif and Wiz found them using OpenAI’s tools, through a program called Patch the Planet. Calif later credited an independent researcher with finding the bug first.

The disclosure didn’t go to plan. Details leaked the day before the scheduled release, so PHP shipped the fixes early on October 21. Exploit attempts were already being seen.

The fixed versions are PHP 8.2.35, 8.3.36, 8.4.27, and 8.5.12. Anything older gets no official release, only patches that hosting companies and Linux distributions can apply themselves.

One point I want to stress, because I almost got it wrong: updating WordPress does not fix this. Earlier this year I patched “wp2shell,” a WordPress bug, by upgrading WordPress. PHP2Shell sits a layer below WordPress, so only whoever controls the server’s PHP can fix it.

Step 1: Find Out Which PHP I’m Running

Everything depended on one number, so I went looking for it.

The hosting dashboard was a dead end. My Network Solutions account shows my plan, my domain, SFTP, and backups. It shows no PHP version and no setting to change it. On a managed WordPress plan, the host controls PHP, not me.

The dashboard also said my WordPress was last updated in 2022. That’s wrong. I’ve upgraded WordPress myself since then, over SFTP. It suggested the host’s records weren’t tracking my site’s software closely.

WordPress had the answer on its front page. The Dashboard showed a “PHP Update Required” warning with my PHP version. You can also find it under Tools → Site Health → Info → Server.

That was bad news on its face. My version was on an older, end-of-life branch, so PHP2Shell got no official release for it. Any fix would have to come from my host applying a backported patch.

Step 2: Protect the Data First

Before changing anything or contacting anyone, I made sure I could recover the site if the worst had already happened.

A fresh backup, locked. I ran a full UpdraftPlus backup (database plus files) and sent it to Google Drive. I also checked Only allow this backup to be deleted manually. That keeps it from being rotated out, and it preserves a snapshot of the site on the night of the incident.

The retention surprise. When the new backup finished, my backup count went from 10 to 9. UpdraftPlus keeps a fixed number of backups, and the new one pushed out the two oldest unlocked sets. I watched retention delete backups in real time.

That made one backup matter more than the rest. The exploit details leaked on October 20 around 10 AM Hawaii time. My October 16 full backup was my last complete copy from before the leak, and it was now next in line for deletion when Friday’s scheduled backup runs.

Downloading it wasn’t one click. UpdraftPlus first has to pull files back from Google Drive. My first database download came through as a 234-byte file, which is about the size of an error message, not a database. Once every part showed “File ready,” the real downloads worked. Uploads alone was split into three pieces, for eight files and 1.3 GB in total.

Then I verified it, in the terminal:

# Is the compressed database intact?
gzip -t backup_2026-10-16-...-db.gz && echo "OK - file is intact"

# Is it really a WordPress dump, not an error page?
zcat backup_2026-10-16-...-db.gz | head -n 5

# Can every zip actually be unpacked?
for f in backup_2026-10-16*.zip; do echo "$f"; unzip -tq "$f"; done

# Are my three accidental database copies identical?
sha256sum backup_2026-10-16*db*.gz

Every check passed. All six zips reported “No errors detected,” and the three database copies had the same SHA-256 hash, so I deleted two. The backup now lives in its own folder on my desktop, off the server and out of reach of any retention schedule.

The lesson: an intact file isn’t the same as a correct file. gzip -t proved the database wasn’t corrupted. Only reading the first lines proved it was actually a WordPress database.

Step 3: Check for Signs of an Intruder

The most common sign of a WordPress break-in is a new Administrator account the owner didn’t create. So I went to Users → Administrator.

There was exactly one Administrator: me. That’s the result I wanted.

The full user list also turned up one inactive account, left over from an old support request. It had no permissions at all, and attackers almost always give themselves full admin rights, so it wasn’t part of this.

I didn’t change anything during the incident. Mid-incident, you leave things as they are until you know what’s normal. Cleaning up unused accounts is on my list for afterward: an unused login is still a login someone could guess or phish.

Step 4: A Clue in the Backup, Then the Host

The most useful finding of the night came from a place I didn’t expect: the first lines of my database backup. UpdraftPlus writes the server details into the header, including the PHP version, the web server, and the Linux distribution the server runs.

That mattered because some Linux distributions had already shipped patched builds of older PHP versions for PHP2Shell. Those patched builds keep reporting the same version number as before.

So the version number alone could never tell me whether I was safe. A patched server and an unpatched one look identical from the WordPress dashboard. Only the host can see the full package version.

Contacting Network Solutions. I used the live chat under Help? → Chat Support. A chatbot answered first, so I gave it a short routing reason with the keywords “WordPress hosting,” “technical support,” “security,” and “live agent.” Then I pasted a prepared message to the human agent. It named both CVEs, the exact patched package to look for, and three specific questions:

  1. Has the distribution’s security update been installed on my server, and what is the package version?
  2. If not, when will it be?
  3. Can my site move to PHP 8.3 or 8.4?

What support said:

  • Server-wide updates related to PHP2Shell were in progress, but the agent had no details yet on what they included.
  • My plan has no option to change the PHP version.
  • No account-specific ticket could be opened during the server work. The chat was logged as ticket I-27178738.
  • For newer PHP, they suggested upgrading to their Essential Hosting plan.

I declined the upgrade for now. A plan change doesn’t protect anyone tonight, and a purchase made in a support chat at midnight is a decision made under pressure.

Where Things Stand

My host is rolling out the fix server-wide, and I’m waiting on written confirmation for my server. Everything on my side of the line is done.

ItemStatus
PHP version and server details identifiedDone
Fresh locked backup, copied to Google DriveDone
Pre-leak Oct 16 backup downloaded and verified locallyDone
Administrator accounts checkedDone, only me
Host contacted, ticket I-27178738Done, server-wide patching in progress
Written confirmation that my server’s PHP is patchedWaiting
Clean up unused accountsAfter confirmation
Move to a current PHP branch for goodComparing options

If I don’t hear back, I’ll follow up using the ticket number. I’ll update this post when I have an answer.

Lessons Learned

Know which layer you own. This is the shared responsibility model from my AWS DVA-C02 studies, in real life. On AWS Lambda, AWS patches the runtime; on EC2, patching is my job. My managed WordPress plan works like Lambda here. I own WordPress, plugins, users, and backups. The host owns PHP. That’s convenient until the host’s layer is the one that’s broken.

A version number isn’t proof. Backported patches mean the same version number can be safe or unsafe. Ask your host for the package version, not the version string.

Watch your backup retention. I nearly lost my last pre-incident backup to an automatic cleanup that was working exactly as designed. Lock or download the backups that matter.

Verify backups, don’t assume them. A 234-byte “database” taught me that. A backup you can’t restore isn’t a backup.

Bring specifics to support. Naming the CVEs and the exact AlmaLinux package got a real answer. My earlier, vaguer chat about PHP went nowhere.

The name says what it does. “PHP2Shell” means turning PHP into a remote shell on the server. That’s the same goal as the web-shell techniques in Black Hat Python, reached here through a memory bug in the engine instead of a bad upload form.

Unused accounts are attack surface. A leftover support login is the WordPress version of a stale IAM user, a classic least-privilege finding.

Sources