A critical PHP vulnerability went public on Wednesday. Our hosting provider couldn't deliver the fix until Friday.
In the meantime, we had a collection of small-business websites to protect, including WordPress sites, online stores, and a learning portal. No panic-button theatrics. No pretending a firewall is a magical force field. Just a practical plan to reduce risk while waiting for the actual patch.
If your hosting provider is running behind, or your website is still clinging to PHP from the digital fossil record, here's what we did, what we found, and what we'd recommend doing next.
Wednesday: The Security News Drops
Security announcements have a familiar rhythm. First, somebody technical starts muttering about a vulnerability. Then the security researchers start publishing details. Then every developer with a production server suddenly remembers where the hosting dashboard lives.
On October 21, 2026, that vulnerability had a name: PHP2Shell.
Two vulnerabilities were disclosed:
- CVE-2026-109618
- CVE-2026-109619
Both received a CVSS v4 severity score of 9.2.
Translation from security-report language into human language: an attacker could send a specially crafted request to a vulnerable PHP site and execute their own code on the server. No account. No password. No friendly “Forgot your password?” email required.
Researchers were already reporting exploitation in the wild, and at least one company had observed an attempted attack days before the public disclosure.
That's not the sort of news you bookmark for later.
PHP powers a huge chunk of the web. WordPress, WooCommerce, Moodle, custom business applications, and countless websites assembled during the golden age of “we'll clean up that code later” all depend on it.
If you run a small-business website, there's a reasonable chance PHP is doing important work behind the scenes while receiving approximately zero appreciation.
The PHP project released fixed versions that same day:
- PHP 8.2.35
- PHP 8.3.36
- PHP 8.4.27
- PHP 8.5.12
Excellent. The fix exists. Time to update and get back to work, right?
Well, not quite.
The Hosting Gap Nobody Puts in the Tutorial
If you manage your own server, updating PHP might be a straightforward package-management task.
If your website lives on shared hosting, things get more interesting.
You don't build the PHP packages yourself. Your hosting provider supplies them, often using packages from an upstream vendor. You choose a PHP version in a control panel and trust that the software behind that dropdown is up to date.
The dropdown is not the server. It's just the dropdown.
For our smaller production sites, we manage a small group of client and company websites under one shared hosting account. The lineup included several WordPress sites, a couple of online stores, a learning portal, and some lightweight static pages.
Our first question was simple:
What PHP build is actually running these websites right now?
Not what the control panel claimed. Not what a configuration file created three years ago said. The version the server was genuinely executing.
Those answers can differ. In our case, some configuration files confidently identified a PHP version that wasn't actually doing the work.
So we tested the real runtime.
For each PHP branch offered by the host, we briefly switched a test site to that branch, checked the build it served, and switched it back.
Here's what we found:
- PHP 8.2: one patch behind the fix.
- PHP 8.3: one patch behind the fix.
- PHP 8.4: one patch behind the fix.
- PHP 8.5: one patch behind the fix.
Every available option was still vulnerable.
Switching to a newer PHP branch, the internet's favorite one-line solution, would have accomplished precisely nothing. At best, we'd have introduced compatibility problems without fixing the security issue.
Our host was waiting for its upstream vendor to ship rebuilt packages. Other shared hosting providers were facing the same delay this week.
That's the gap: the vulnerability is public, attacks are happening, the fix exists, but you can't install it yet.
Waiting for an email notification was not the strategy we wanted for our clients' websites.
How We Held the Line
When you can't fix the root cause immediately, you reduce the attack surface, make recovery possible, and keep an eye on what's happening until the real fix arrives.
1. Backups first. Heroics later.
Before touching the configuration, we backed up the entire hosting account.
Every file. Every database.
Why? Because security hardening can break things. A configuration change that looks harmless might interfere with a checkout flow, a plugin, or an application that hasn't been updated since the last time anyone remembered its password.
If something went sideways, we wanted a clean recovery path.
Rule number one of incident response: don't turn your attempted fix into the next incident.
2. Disable a feature the sites didn't need
The published attack paths relied on PHP's session upload-progress feature, which many websites never use.
We added this setting to every PHP site's configuration:
session.upload_progress.enabled = Off
Then came the important part: verification.
We checked the setting through the running PHP environment on every site. Saving a configuration file and successfully changing the server's behavior are two very different things.
3. Put a firewall in front of the high-value target
Two of our online stores process real orders, and two other sites run ads. That made them particularly important targets to protect.
We routed them through a CDN with a managed web application firewall (WAF) that had already published PHP2Shell protection rules.
While configuring the CDN, we also tightened the SSL mode from Flexible to Full (strict).
Security changes are only useful if the application still works, so we tested the storefronts, product pages, add-to-cart functionality, and conversion tracking afterward.
A secure checkout that can't accept orders is technically an interesting outcome, but not one the business owner is likely to celebrate.
4. Built a tiny watcher for the patch
Instead of repeatedly refreshing the hosting provider's status page, we set up a watcher.
Our watcher kept an eye on the PHP build the sites were running and triggered when it showed the fixed release.
No guessing. No manually refreshing a dashboard every fifteen minutes. Just a simple check for the condition we cared about.
One caveat: some hosts backport security fixes without changing the displayed version. A version watcher is useful, but it isn't universal proof of patch status.
A quick reality check on temporary fixes
Turning off upload progress can block known PHP2Shell attack paths. It does not guarantee protection against every possible variant.
A WAF can block attacks covered by its rules. It cannot guarantee that every malicious request will be caught.
Neither measure replaces the actual PHP security fix.
These controls buy time. They reduce exposure while you wait for the root cause to be addressed.
The clock is still ticking until the vulnerable software is properly fixed or otherwise protected by a verified vendor solution.
The Midnight Knock: Had Anyone Already Gotten In?
Hardening is the part of incident response that gets the attention.
What if someone got in before we started locking things down?
We ran a compromise check across the WordPress sites.
File changes across every site
We listed every file and flagged files whose modification times or metadata indicated changes since the day before disclosure.
There were tens of thousands of files per site.
Attackers can sometimes manipulate file modification timestamps to make changes look older than they are. File change metadata can provide an additional clue, although no single timestamp is definitive proof of when a file was altered.
WordPress core and plugin checksums
We compared changed WordPress core and plugin files against official published checksums.
Thousands of changed plugin files turned out to be legitimate updates. Every one of those checked files matched the official release.
A changed file is a reason to investigate, not automatic proof of an intrusion.
The uploads directory
PHP files hiding in an uploads directory are a classic warning sign.
We inspected the uploads folders and found only old, harmless placeholder files.
No suspicious new PHP files turned up in that check.
Scheduled tasks
We reviewed the scheduled jobs running across the sites.
Exactly one job was present, and it was known and legitimate.
No mysterious scheduled tasks waiting to surprise us later.
Access logs: where the story got interesting
On one site, shortly before midnight in our local time zone, a single IP address sent eight requests carrying the exploit's fingerprint.
This happened hours before most people had heard the name PHP2Shell.
The requests even used a user-agent string that practically introduced itself by naming the CVE identifiers.
Subtle, this was not.
All eight requests received the same response: the site's ordinary homepage, with the same content and response size that any normal visitor would receive.
The visitor didn't make any follow-up requests.
We found no new files, no evidence of tampering in the checks we performed, and no signs of outbound communication associated with the activity.
Based on those observations, we found no evidence that the requests had successfully compromised the site. The behavior was consistent with someone probing the site and moving on.
A normal-looking response is reassuring, but it cannot independently prove that an exploit failed. Logs, file checks, integrity checks, and other evidence all contribute to the assessment.
The bonus discovery nobody ordered
While reviewing the sites, we also found an unrelated but embarrassing problem.
One site had an old diagnostic file publicly accessible on the web. Anyone who requested it could see the server's full PHP configuration.
It wasn't evidence of a breach, but it handed potential attackers a useful map of the environment.
We removed it.
Security reviews have a habit of finding the things that have been quietly sitting in a forgotten folder for years. The vulnerability gets everyone's attention, and suddenly that old test.php file looks a lot less charming.
Friday: The Patch Finally Arrives
Two days after disclosure, our watcher triggered.
It showed PHP 8.2.35, one of the fixed releases.
The upstream vendor had shipped the updated package, and because the hosting account used the provider's default PHP package, every site picked up the fix at once. We didn't need to switch each site individually.
But we weren't finished just because the version number looked right.
Here's the post-patch checklist we followed.
Verify the rollout
We confirmed the fixed build on every site that exposed its PHP version and documented that the remaining sites shared the same package.
We also checked every domain on the account to make sure the websites loaded normally.
A patch can fix a security problem and still introduce a compatibility problem.
Remove temporary access
We deleted the temporary access we had created during the response.
Temporary accounts and permissions have a sneaky habit of becoming permanent if nobody remembers to clean them up.
Remove the extra CDN hop
Once the origin server was patched, we took the store back off the CDN.
The proxy had started returning occasional connection errors, and the additional layer was no longer needed for the temporary PHP2Shell mitigation.
We didn't want to replace a security concern with an availability problem.
A CDN and WAF can still be useful long-term protections, but every additional component needs to justify its operational cost and reliability impact.
Keep the upload-progress setting disabled
We left session.upload_progress.enabled turned off.
None of the sites used the feature, so leaving it disabled introduced no known functional downside for our setup while preserving an additional layer of hardening.
The result: zero client downtime.
The amount of sleep we lost is a separate metric, and one we have chosen not to publish.
Your PHP2Shell Action Plan: What to Do If Your Host Hasn't Patched Yet
Hosting providers don't all update their packages on the same schedule.
If your provider hasn't delivered the fixed build, here's the checklist we'd follow again.
1. Back up the entire site
Back up your files and databases before changing anything.
Know where the backup is stored, confirm that it completed successfully, and understand how you would restore it.
A backup you have never tested is a hopeful theory about recovery.
2. Find the PHP version actually running
Check the server's response headers if they expose the PHP version. If necessary, a temporary diagnostic file can help identify the runtime.
If you create one, use a random filename, restrict access where possible, retrieve the information you need, and delete the file immediately.
Do not leave a phpinfo() page publicly accessible. It can expose detailed configuration information to anyone who finds it.
Also, don't rely exclusively on the displayed version number. Some hosting providers backport security fixes while retaining an older version string.
Ask your host directly whether the installed build includes the PHP2Shell fix and request confirmation.
3. Check every PHP branch your host offers
If one available branch has been patched and your application supports it, switching may be the quickest solution.
If every available branch is still vulnerable, switching versions just to choose a bigger number is unlikely to help.
Unnecessary version changes can introduce new problems without removing the original risk.
4. Disable features your application doesn't use
For sites that don't require upload progress, consider setting:
session.upload_progress.enabled = Off
This may be configurable through a per-site .user.ini file or your hosting provider's PHP settings interface.
Test the change and verify the effective runtime setting.
Some advisories also mention memory-limit adjustments. Treat those carefully on shared hosting and test before applying them. Configuration changes should be guided by the actual advisory and your application's requirements, not copied blindly from a random forum post.
5. Add a WAF where it matters most
A CDN or host-level web application firewall with PHP2Shell protection rules can add a useful layer while you wait for the patch.
Prioritize systems that handle payments, logins, personal information, or other high-value activity.
Remember that a firewall is a compensating control, not a replacement for fixing vulnerable software.
6. Look for evidence of compromise
Review the areas attackers commonly touch:
- New or recently modified PHP files.
- Unexpected PHP files in upload directories.
- Unfamiliar WordPress administrator accounts.
- New or unexplained scheduled tasks.
- Suspicious requests in web access logs.
- Unexpected changes to WordPress core or plugin files.
Compare files against trusted checksums where available. Investigate anomalies rather than assuming every change is malicious.
And remember that a clean result from one check does not prove the entire site is clean.
7. Open a support ticket
Give your host the CVE identifiers, the build you're running, and the fixed build you need.
Ask whether a backported fix is available and when the updated package will reach your account.
8. Monitor the patch and verify it
When the fix arrives, check the runtime build or obtain confirmation that the installed package contains the security fix.
Then test your key pages and workflows.
For an online store, that means checking the storefront, product pages, cart, and checkout.
“It's probably patched by now” is not a verification strategy.
9. Clean up after the emergency
Remove diagnostic files, revoke temporary accounts and permissions, and move verified backups off the hosting server.
Document what changed so the next person isn't left reverse-engineering your emergency response.
Future you has enough problems already.
Stuck on Old PHP? We Need to Talk.
Your application runs on PHP 8.1, PHP 7.4, or perhaps PHP 5.6 because the code simply refuses to cooperate with anything newer.
Maybe it's a custom booking system. Maybe it's an inventory application built in-house. Maybe it's a plugin whose developer disappeared in 2019 and whose documentation consists of three screenshots and a forum post.
Whatever the reason, you can't safely assume the old runtime will protect itself.
PHP 8.1 and earlier are end of life, and the PHP project is not releasing PHP2Shell fixes for those branches.
Protection depends on whether a vendor supplies backported security fixes or on other compensating controls you put around the application.
Ask whether your host backports security fixes
Some hosting platforms continue patching older PHP branches themselves.
Ask your provider explicitly whether your installed version contains the PHP2Shell fix. Request a written answer that identifies the affected build or package.
An old version number doesn't automatically prove that a backported fix is absent, just as a newer version number doesn't automatically prove that every relevant security issue is addressed.
Get the actual package status.
Put a firewall in front of the legacy application
A properly configured WAF can help reduce exposure, particularly when the underlying application cannot be updated immediately.
This is especially valuable for systems that handle payments, sensitive records, or administrative functions.
Don't treat it as a permanent excuse to leave the software unmaintained.
Isolate the application
Don't let a fragile legacy application share unrestricted file permissions, database credentials, or hosting-account privileges with your primary website.
Use separate accounts or environments where possible, restrict permissions, and limit access to the resources the application actually needs.
If the old application is compromised, the goal is to prevent that incident from becoming a guided tour of every other website you operate.
Reduce the exposed attack surface
Lock down administrative areas behind authentication or IP allowlisting where practical.
Remove unused endpoints. Disable PHP features the application doesn't need. Restrict access to sensitive resources.
The fewer unnecessary doors your application exposes, the fewer opportunities an attacker has to exploit them.
Put a migration date on the calendar
“Someday we'll upgrade that old application” is not a migration plan.
Start by running compatibility checks against a supported PHP version. Identify deprecated functions, incompatible dependencies, and the specific features that break.
Then estimate the work.
Sometimes the fix is a handful of deprecated function replacements. Sometimes a dependency needs an update. Sometimes the one feature your business still uses can be rebuilt more cheaply than the entire legacy system can be maintained.
You don't necessarily need a ground-up rewrite. You do need a realistic path away from unsupported software.
Set a deadline and assign an owner.
Back it up like you mean it
Legacy applications are often the systems nobody knows how to rebuild.
Document the database, dependencies, configuration, scheduled tasks, and restoration procedure. Keep verified backups somewhere separate from the production server.
The less maintainable the application, the more important a reliable recovery plan becomes.
A Brief Archaeological Tour of GREG_OLD_PHP_DO_NOT_TOUCH
Every small-business hosting account has a little archaeology.
You open a file manager expecting a tidy application directory and discover an ecosystem that has evolved entirely without documentation.
Perhaps you've encountered one of these classics:
- A folder called
GREG_OLD_PHP_DO_NOT_TOUCH. Nobody remembers Greg. Greg left in 2017. The folder is apparently still load-bearing. index_final.php,index_final2.php, andindex_final_REAL_use_this.php. Naturally, the live site uses none of them.- A scheduled task that runs every five minutes, does something mysterious, and “only Dave knows what it does.” Dave is unreachable. Dave may be a legend.
- A publicly accessible
test.phpfile that's been online since the Obama administration. - A code comment reading
// temporary fix, remove before launch, dated 2012. - A configuration file whose entire documentation is a sticky note on a monitor in the back office. The sticky note has fallen off.
We laugh because the situation is painfully familiar.
But the underlying problem isn't funny: unknown code is difficult to maintain, difficult to secure, and difficult to upgrade.
You can't confidently upgrade PHP if nobody knows what depends on the old runtime.
You can't reliably identify a suspicious file if the server is already full of mysterious files.
And when a serious vulnerability arrives, you can't make quick, safe decisions if every change risks breaking a system whose original developer vanished a decade ago.
The fix is an inventory.
List every website, application directory, scheduled task, plugin, PHP version, and important dependency. Record who owns each component and why it exists.
Once Greg's folder has a documented purpose and a responsible owner, it stops being server folklore. You can maintain it, upgrade it, isolate it, or finally delete it.
All four options are better than crossing your fingers every time a security advisory appears.
What PHP2Shell Taught Us
The week went well, but not because we got lucky.
A few unglamorous things made the difference:
- We could produce a full backup when we needed one.
- We checked the actual runtime instead of trusting the control panel.
- We knew which websites lived on the hosting account.
- We applied temporary hardening while waiting for the official fix.
- We investigated whether an attacker might already have accessed a site.
- We treated hardening and compromise assessment as two separate jobs.
- We verified the patch and tested the sites afterward.
- We removed the temporary access we created once the work was done.
None of these steps is particularly glamorous.
There's no cinematic montage of developers typing furiously into terminal windows. No dramatic green text cascading down a monitor.
Just backups, configuration checks, logs, checksums, careful testing, and a healthy suspicion of files nobody remembers creating.
If you don't know which PHP version your website runs, whether your host has applied the relevant fix, or what that strangely named folder contains, those are excellent places to start your next maintenance review.
How This Connects to Synapticraft Services
Synapticraft helps small businesses keep their web infrastructure in better shape through:
- WordPress websites: Development, maintenance, and support for business-critical sites.
- Secure industry sites: Websites designed with security and operational requirements in mind.
- Monthly reporting: Visibility into your website's status, changes, and ongoing needs.
If you're dealing with a WordPress site that may already be compromised, start with our WordPress cleanup checklist or our broader guide to WordPress security in the AI era.
No security service can honestly guarantee that a website will never be compromised.
A good security process should tell you what was checked, what changed, what remains uncertain, what still needs attention, and which actions require your approval.
Start here
Not Sure Whether Your Website Is Patched?
Let's take a look under the hood.
Send us your website URL, the name of your hosting provider, and whether you have hosting-panel or WordPress administrator access.
If your server contains a folder called GREG_OLD_PHP_DO_NOT_TOUCH, feel free to mention that, too.
We promise not to judge.
We'll help you establish what's running, identify the next steps, and figure out whether your website needs a routine maintenance check or a more urgent security review.
Because your website should spend its time serving customers, not auditioning for a cybersecurity incident report.
Ask About a PHP Security Check