The PHP2Shell vulnerability gave most UK security teams a tidy emergency change window, a patched version number and a false sense of completion. Patching was the easy part. The harder question is what an attacker can still see and reach once your change window closed, because a fixed package version says nothing about the hosts nobody inventoried, the runtime that was never restarted, or the webshell dropped during the days before your host got round to it.
These are the five checks worth running after the patch, in the order that reduces real risk fastest.
What PHP2Shell Is, and Why Patching Is Only Step One
PHP2Shell is the name attached to a pair of flaws published as CVE-2026-109618 and CVE-2026-109619, both carrying a CVSS base score of 9.2, which chain together into unauthenticated remote code execution against affected PHP installations. Fixes landed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Branches earlier than 8.2 sit outside security support, so for those estates the answer is migration, not patching. Check the current advisory and PHP's supported versions page against your own branch before you accept anyone's assurance that a server is clean.
The CVSS score is not the interesting number. The exposure window is. Mass scanning for a new unauthenticated RCE typically begins within days of a public fix, because the patch itself tells attackers where to look. If your hosts were reachable and unpatched for even a short period after disclosure, then "patched"and "not compromised"are two separate statements, and only one of them has been proven.
The arithmetic most asset lists get wrong
W3Techs' long-running survey of server-side languages has for years put PHP above 70% of sites where the language can be identified. Whatever your internal inventory says, your organisation almost certainly runs more public-facing PHP than it has recorded, because PHP is what agencies, CMS platforms, plugin ecosystems and cheap hosting default to. Most organisations do not have a complete view of their external attack surface, and PHP is where that gap bites hardest.
Genuinely exposed estates cluster in predictable places: PHP-CGI setups nobody has touched since commissioning, older shared hosting where the provider controls the branch, and sites pinned to a legacy version because a plugin broke on upgrade in 2021 and the fix was deferred indefinitely.
Check 1: Find Every Internet-Facing PHP Host You Forgot You Had
Start from the outside. A CMDB that was accurate eighteen months ago is a document, not an inventory, and the hosts that cause real damage are rarely the flagship site.
They are the 2019 campaign microsite still running on a low-cost VPS somebody expensed. The regional domain kept alive after an acquisition. The staging subdomain carrying a live copy of the production database because that was the quickest way to reproduce a bug.
Build the list from DNS records, certificate transparency data and external discovery rather than from what anyone remembers deploying. Certificate data in particular catches subdomains that were never added to any register, because somebody had to request a certificate to make the site work. Map what you find geographically as well, which is how regional hosting provisioned by a local marketing team surfaces before an attacker's scanner finds it. This is the discovery discipline behind attack surface drift and the ways inventories fall behind, and PHP advisories are exactly when that drift becomes expensive.
Then triage hard. Public login pages, file upload paths, contact forms writing to a database and anything running an admin panel go to the top of the queue. Static brochure sites with no write path go last, regardless of how senior the person who owns the brand is.
Check 2: Prove the Running Runtime Is Fixed, Not Just the Package
This is where most remediation programmes quietly fail. The installed package version, the CLI binary you query over SSH and the version PHP-FPM is actually serving to the internet can all report differently. A server that looks patched in a terminal will keep serving a vulnerable runtime until the FPM pool is restarted, or until a container image is rebuilt and redeployed rather than simply restarted from the same cached layer.
So the evidence you need is not a package manager output. Ask for the branch and build serving traffic, the date the fix was applied, and confirmation that the pool or container was recycled afterwards. For managed platforms and vendored builds, that evidence has to come from the provider in writing.
Then verify from outside, using both infrastructure and web application scanning, because the two see different things: one confirms what the host exposes on the network, the other confirms what the application layer behaves like. Deduplicate the output before it reaches your ticket queue, or one host behind three hostnames and two IP addresses will generate five tickets and burn a day of engineering attention on triage rather than fixes.
Keep the dated verification record. Confirming the fix, with a timestamp you can put in front of a board or an auditor, is the step almost every remediation programme skips, and it is the only thing that distinguishes "we patched"from "we checked".
Check 3: Hunt for Webshells and Persistence Left Behind
A patch closes the door. It does not remove anyone already inside. If an attacker gained code execution during the exposure window, your update has changed nothing about their access.
Look for:
- An unexpected .php file sitting inside an uploads or media directory that should only ever hold images and documents
- Obfuscated loaders using eval, base64 decoding or long encoded strings inside otherwise ordinary files
- Theme, plugin or core files with modification timestamps that do not match your deployment history
- A new cron entry, especially one calling PHP or curl
- Outbound connections from a web host that should only ever serve inbound traffic
Where you find persistence, reinstating from a known-good pre-incident backup beats cleaning in place. Cleaning in place assumes you found everything, and webshells are routinely planted in pairs so the second one survives the cleanup of the first. If the backup predates the compromise and the configuration is reproducible, rebuild.
Widen the search beyond the host too. Freshly registered lookalike domains are often staged alongside an exploitation campaign to host second-stage payloads or run phishing against the same victim set, which is why a domain spoofing detection playbook belongs in the same incident, not in a separate workstream three weeks later.
If you confirm unauthorised access to a host holding personal data, the UK GDPR clock starts from the moment you become aware, not from the moment remediation finishes. That gives you 72 hours to notify the ICO where the breach is reportable, and the ICO's own breach reporting guidance is the reference to work from. Escalate to full incident response at the point you find persistence, not at the point you finish investigating it.
Check 4: Treat Config-File Credentials as Already Leaked
Unauthenticated remote code execution on a web host means every secret readable by the web user should be treated as exposed. On a typical PHP estate that means database credentials, SMTP logins, API keys, payment gateway secrets and whatever session data the application keeps on disk.
Sequencing matters more than speed here, and this is the trap. Rotating secrets while an attacker still has code execution simply hands over fresh credentials, neatly, with the new values delivered through the same shell. Confirm eviction first. Then rotate, in order of blast radius: anything granting access to other systems, then payment and messaging credentials, then application-local secrets.
After rotation, go looking for the old ones. Cross-check leaked credential data and stealer log triage for your domains and staff accounts covering the exposure window, and add the affected admin and developer identities to people monitoring so reuse of those credentials against other services gets flagged rather than discovered later.
One more signal worth reading. Mass-scanning kits and working exploit chains circulate in hacker and ransomware Telegram channels well before clean public write-ups appear. Monitoring that chatter is how you tell opportunistic internet-wide scanning apart from targeted interest in UK hosts or your specific sector, and the difference changes how fast you need to move. If you intend to monitor Telegram for exploit chatter yourself, read how dark web Telegram channels actually work first, because keyword alerts on a handful of public groups produce noise, not intelligence.
Check 5: Chase Supplier and Agency-Hosted PHP
Supplier-hosted PHP is the blind spot nobody owns. The agency controls the runtime. The hosting provider controls the branch. Your business owns the risk, the data and the regulator's attention.
Marketing sites built by an agency, white-label customer portals, e-commerce plugins, hosted booking pages and payment flows all sit in this category. Ask each supplier, in writing, for four things:
- The PHP branch and exact patch level now serving traffic
- The date the fix was applied, and whether the FPM pool or container was rebuilt
- Whether logs were reviewed for the exposure window, and what was found
- Whether any credentials or keys shared with your systems were rotated
Set a response deadline you can actually enforce: 48 hours for anything handling payments or personal data, five working days for the rest. Then track the answers against supplier threat scoring and accreditations such as ISO 27001 rather than accepting a green status page, which reports availability, not patch state. A page that says "all systems operational"is telling you the vulnerable runtime is up.
Reporting Progress Without Drowning Leadership in CVE Numbers
Executives do not want the CVSS vector. They want four numbers: hosts found, hosts patched, hosts verified from outside, and hosts owned by third parties where you are still waiting on an answer. That last figure is usually the one that prompts a useful conversation, because it is the only one your team cannot fix alone.
Report weekly on what has changed rather than restating the total. New PHP hosts appear constantly, and a host that was patched in March can be re-exposed by a rollback, a restored snapshot or a rebuilt container pulling a stale base image. Push verified findings into Slack, Jira, Teams or your SIEM so remediation is tracked against an owner instead of circulating as an email thread that dies when somebody goes on leave.
The real outcome from PHP2Shell is not a closed ticket. It is deciding that the next advisory starts with a current asset list rather than a fortnight of discovery under pressure. Continuous external discovery, change detection and credential exposure monitoring turn an emergency into a filtered queue, and that shift is what separates teams who respond in days from teams who are still finding hosts a month later. If you want to see what your estate looks like from an attacker's perspective, start with a map of your external attack surface and work inwards from there.
Frequently Asked Questions
Which PHP versions fix the PHP2Shell vulnerability?
The fixes for CVE-2026-109618 and CVE-2026-109619 were released in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Anything on an earlier supported branch should be moved to the corresponding fixed release for that branch. Confirm against the official PHP release notes for your branch before signing off, since point releases continue after the initial fix.
How do I tell whether my PHP host was actually exploited before I patched?
Compare web server and application logs across the exposure window for unusual POST requests to unexpected paths, then check the filesystem for new or modified PHP files, particularly inside upload directories. Look for new cron entries and any outbound connections from a host that should only serve inbound traffic. If you find anything that cannot be matched to a deployment, treat it as an incident and escalate rather than cleaning it quietly.
What should I do if my PHP version is 8.1 or older and no patch exists?
Branches earlier than 8.2 have no supported fix path, so the answer is migration rather than patching. In the meantime, reduce exposure: restrict the host behind authentication or a WAF, disable file upload paths you do not need, and take genuinely unused sites offline entirely. A decommissioned microsite is a solved problem; a permanently unpatched one is not.
Does patching PHP remove a webshell an attacker already installed?
No. Patching closes the entry route and leaves any existing access untouched, because a webshell is just a file the server will happily execute whatever version of PHP is running. Eviction requires finding and removing the persistence, or rebuilding from a backup that predates the compromise, and then rotating every secret the host could read.
Who is responsible for patching PHP on an agency-built website?
Contractually it depends on the hosting arrangement, which is why it needs to be established in writing before an advisory lands rather than during one. Practically, the agency or hosting provider applies the patch and your organisation carries the regulatory and reputational risk if they do not. Ask for the branch, the patch date and confirmation that logs were reviewed, and record the response.













