Vulnerability ManagementThreat IntelligencePHPIncident ResponseAsset Discovery

PHP2Shell: Attackers Were Probing It Four Days Before the Patch

Venkat PothamsettyOctober 23, 202614 min read
PHP2Shell: Attackers Were Probing It Four Days Before the Patch

On 21 October, PHP shipped an emergency fix for two critical bugs in the interpreter itself. Within hours, government sites in Germany, France, the Netherlands and Finland were switched off as a precaution. A couple of big Japanese banks paused some services. Wikimedia and the Internet Archive scrambled too. Reuters PHP Group

That kind of reaction is usually reserved for a broken router or a cloud outage, not a programming language.

And the patch wasn't the start of it. Amazon's MadPot honeypots caught someone trying a PHP2Shell exploit on 17 October, four days before anyone outside the disclosure process knew about it. AWS saw more attempts in the early hours of the 21st. They haven't said any of those early attempts worked against a real system, but the point stands: attackers had it before defenders did. AWS Threat Intelligence

Patching PHP is easy. Knowing every place PHP is running is the hard part, and that's what most of this post is about.

A quick note before we start: there's a lot of noise around this incident. We try to keep four things separate below: exploit attempts, vulnerable software, sites taken offline as a precaution, and confirmed breaches. They're not the same thing, and mixing them up leads to bad decisions.

What the bugs are

There are two CVEs, both rated critical (CVSS v4.0 9.2):

  • CVE-2026-109618. When PHP runs out of memory partway through a request, it can be left holding half-built internal data. The cleanup code then trips over it.
  • CVE-2026-109619. Some request-owned references can outlive the memory they point to. If a worker process gets reused, the next request can end up reading stale data.

Both bugs sit in the interpreter, not in WordPress, Drupal or your own code. So a fully patched CMS running on a vulnerable PHP build is still exposed. Wiz, who found the issues, showed working exploit chains against common CMS setups and showed memory could leak as well. Whether a particular site is exploitable depends on how PHP is wired up: worker lifetime, memory limits, and which SAPI is in use. PHP calls out Apache mod_php as especially exposed, and says PHP-FPM, php-cgi, FrankenPHP and LiteSpeed setups all need the fix. Wiz PHP Group

The short version: updating WordPress doesn't fix this. Updating PHP does. A WAF rule can block some known attack paths, but it isn't a substitute for the patch. AWS WAF

Who went offline

Here's what was reported in the first couple of days:

  • Germany: government sites run or supported by ITZBund
  • France: Interior Ministry prefecture websites
  • Netherlands: government services and other public sites, including activity reported at the Port of Rotterdam
  • Finland: public services run by the state IT provider Valtori
  • Czech Republic and Belgium: government and institutional sites
  • Japan: some services tied to the Ministry of Finance, the National Tax Agency, the weather service, MUFG and Nomura
  • Global: Wikimedia and the Internet Archive

Most of these were shutdowns while teams patched. A bank pausing its website doesn't mean its payment systems were breached. Reuters

A community-run outage tracker had logged 56 interruptions by 15:52 UTC on 22 October. Twenty-four were in the Netherlands, 11 were global, and 5 were in Japan. By type, it counted 25 general websites, 17 government sites, 11 platforms and 3 universities. At that point 50 were back up, 6 were still down, and the median outage ran just over five hours. Outage tracker

Rows in a 56-entry crowdsourced outage tracker (snapshot 22 Oct 2026, 15:52 UTC). “Global / multi-region” is not a country. This is not an internet-wide sample or a breach count.
Rows in a 56-entry crowdsourced outage tracker (snapshot 22 Oct 2026, 15:52 UTC). “Global / multi-region” is not a country. This is not an internet-wide sample or a breach count.

Don't read too much into the Netherlands number. A crowdsourced list reflects who's contributing and which outages make the news. It doesn't show where attackers hit hardest.

What about India?

CERT-In put out advisory CIVN-2026-0510 on 21 October flagging the PHP bugs as critical. That's confirmed. What we haven't seen is any credible report naming an Indian government site or bank as actually compromised through PHP2Shell. CERT-In

If you're defending an Indian organization, the risk is less about a known attack and more about PHP you've lost track of:

  1. Government estates. Department portals, tender and procurement sites, vendor-maintained services, and old projects that never made it into a central inventory.
  2. Banks and financial services. Support sites, marketing microsites, internal admin panels, acquired web properties and outsourced vendors. Core banking probably isn't on PHP, but plenty around it might be.
  3. Universities and public institutions. Faculty and research servers, and old admin apps with no clear owner.
  4. Appliances and commercial software. Web consoles that bundle their own PHP and never show up in an OS-level scan.

These are where we'd start looking, not claims about anyone in particular. The Japanese bank pauses are a useful example of what a cautious response looks like. They don't mean an Indian bank was hit.

The timeline

The patch came out in October, but the work started months earlier. Wiz found the problem on 19 August and reported it to PHP on the 24th. AWS spotted an exploit attempt on 17 October, before the fix was public. Wiz AWS PHP

DateWhat happenedWhat it doesn't tell us
19–24 AugWiz finds the bugs, confirms them in lab setups and reports to PHP.Nothing about real-world victims.
21 SepPHP acknowledges the reports.Nothing about compromise.
17 OctAWS MadPot records an exploit attempt.AWS hasn't shown a successful attack on a customer.
20 OctWord of an urgent PHP security release gets out.Not every exposed site was targeted.
21 OctPHP ships the fix; sites start going offline to patch.A shutdown isn't proof of a breach.
22 OctPatching and restoration continue.Crowd reports can lag or be wrong.

What this means for your log searches: start at 17 October at the latest, and go further back if you have the logs. AWS's first sighting isn't necessarily the first attempt anyone made. AWS also warned that some of the IPs it shared are anonymizing infrastructure used by lots of unrelated traffic, so use them as leads, not a blocklist. AWS

How big is the exposure?

You'll see two big numbers quoted. They measure different things, so don't add them up or compare them directly.

22.6 million comes from Palo Alto's Unit 42. It's the number of internet-facing instances their scanning flagged as potentially vulnerable. An instance isn't the same as a website, and it isn't a confirmed infection. Unit 42

167 million comes from Qualys. It's the number of PHP package installations they see across about 12,000 customers. Of the 155 million where the version is known, roughly 110 million are on end-of-life branches and 44 million on supported ones. Qualys says 73% sit on internet-facing machines, and about 199,000 were patched in the first 12 hours. Qualys

22.6M exposed instances (Unit 42) and 167M package installations (Qualys) are different units and are not additive. The Qualys split is roughly 110M EOL + 44M supported among 155M version-identifiable installations.
22.6M exposed instances (Unit 42) and 167M package installations (Qualys) are different units and are not additive. The Qualys split is roughly 110M EOL + 44M supported among 155M version-identifiable installations.

Neither number tells you how many government sites are vulnerable. One web app can pull in several PHP installs, and one server can have several versions on it. What both numbers do tell you: there's a lot of old PHP out there, and much of it faces the internet.

Finding PHP where it actually runs

The rule that matters most: check the PHP that's serving web requests, not just the PHP that shows up in your package list. For each system, write down where it is, who owns it, which PHP build and SAPI it runs, where that build came from, whether it's reachable from the internet, proof that it's patched, and what logging you have.

Virtual machines and bare metal

On machines you manage, compare what the package manager says with what's actually loaded:

# CLI version only — not necessarily what the web server uses
php -v 2>/dev/null
php-fpm -v 2>/dev/null

# Packages installed through the OS
(dpkg -l 'php*' 'libapache2-mod-php*' 2>/dev/null | grep '^ii') || true
rpm -qa 'php*' 2>/dev/null

# What's actually running
pgrep -a php-fpm
apachectl -M 2>/dev/null | grep -i php

# PHP installed outside the package manager
find /opt /usr/local -type f \( -name 'php' -o -name 'php-fpm*' \) 2>/dev/null

A patched php -v doesn't mean Apache is safe. The CLI, mod_php and PHP-FPM can each be a different install. If you're running this across production, think about how long the find will take and what permissions it needs.

On Windows, look for hand-copied C:\PHP\php.exe folders and check the IIS FastCGI handler mappings. If PHP isn't listed in Add/Remove Programs, that doesn't mean it isn't on the machine.

Containers and Kubernetes

The PHP inside a container has nothing to do with the node's OS. List the images you're actually running, pin their digests, and scan them:

kubectl get pods -A \
  -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | sort -u

trivy image --scanners vuln myregistry/app:latest
syft myregistry/app:latest -o spdx-json > app.sbom.json

# Only where you're allowed to exec into pods:
kubectl exec -n my-namespace my-pod -- php -v

Watch out for latest. The tag may point at a newer build than the one actually deployed. Fix the base image, rebuild everything built on it, and redeploy. If you skip the rebuild, the next rollout brings the bug right back.

Cloud-managed PHP

On Azure, Resource Graph will find App Service sites running PHP across all your subscriptions:

resources
| where type =~ 'microsoft.web/sites'
| extend phpRuntime = tostring(properties.siteConfig.linuxFxVersion),
         windowsPHP = tostring(properties.siteConfig.phpVersion)
| where phpRuntime contains 'PHP' or isnotempty(windowsPHP)
| project name, resourceGroup, subscriptionId, phpRuntime,
          windowsPHP, state=tostring(properties.state)

This tells you what's configured. PHP|8.4 doesn't tell you whether you're on 8.4.27. On AWS, check Systems Manager, EC2 inventory, Elastic Beanstalk platform versions and your container registries. On Google Cloud, check App Engine runtime settings and the image digests behind Cloud Run.

For managed platforms, confirm the live version through the provider's tooling and advisories, and make sure the service has restarted onto the patched platform. And if you spin up a phpinfo() page to check, take it down afterwards.

A handy trick: CloudTrail user agents

When PHP code calls AWS through the AWS SDK for PHP, the user agent often includes the PHP version, e.g. lang/php#8.2.34. If you already log those CloudTrail events, you get a rough history of which PHP versions were running and when.

It's a hint, not proof. The process making SDK calls might not be the one serving web traffic, user agents can be changed, and some CloudTrail data events are off by default.

Appliances, vendors and outsourced hosting

Ask your vendors directly: do they ship PHP, which build, and do they have an advisory or SBOM? Your scanner can't see inside a sealed appliance or someone else's hosting. Until you have an answer, treat those systems as unknown, not clean.

Spotting exploitation attempts

For any internet-facing system running a vulnerable build, look at web logs, PHP errors, worker behavior and endpoint telemetry together. Wiz's research points to multipart uploads, session upload-progress handling and fatal errors during request cleanup as good places to look. Wiz AWS

Things worth investigating:

  • Bursts of multipart/form-data POSTs to PHP routes, especially malformed ones or ones hitting session upload-progress
  • Spikes in HTTP 500s, PHP memory-limit errors, worker crashes or unusual worker restarts
  • Web server or PHP processes spawning children, making outbound connections, touching files or credentials, or setting up persistence
  • WAF blocks and request-body inspection hits (WAFs often sample or truncate bodies, so expect gaps)

None of these on its own means you've been popped. Normal uploads are multipart, 500s happen all the time, and a fileless attack might never spawn a shell. What matters is the sequence of events, how it compares to your normal baseline, and whether the host shows matching activity. If you think something got in, preserve logs, disk and memory before you rebuild. Patching won't remove an attacker who's already there.

Cloudflare and AWS have both published WAF guidance. Neither claims a WAF rule fixes the problem. Cloudflare AWS WAF

Which versions fix it

BranchFirst fixed versionWhat to do
PHP 8.58.5.12Update, or use a verified vendor build
PHP 8.48.4.27Update, or use a verified vendor build
PHP 8.38.3.36Update, or use a verified vendor build
PHP 8.28.2.35Update, and plan your move off 8.2
PHP 8.1 or olderNo upstream releaseMigrate, or get a vendor backport that covers both CVEs

PHP has published source backports for some older branches. Linux distros also often backport fixes without changing the version number. So a version check against distro packages can flag systems that are actually fixed. Check that your vendor's advisory names both CVEs. PHP Group Dutch NCSC

If you can't patch an exposed service quickly, lock down access, apply PHP's recommended mitigations, or take it offline until you can. After patching, restart the workers and confirm the version the web server is actually using, not just the CLI.

A checklist for closing it out

Find it, confirm it, prioritize it, contain it, patch it, hunt, then check your work. Do the hunting alongside patching for anything exposed or suspicious, not after.

Only mark a system as fixed when you can say:

  • which workload it is, who owns it, and what build it runs
  • which web SAPI is serving and which fix is applied (upstream release or verified backport)
  • whether it's reachable from the internet, including through load balancers or side routes
  • that vulnerable container images were replaced by digest, not just retagged
  • that workers were restarted and someone checked the result
  • that you've reviewed logs back to mid-October, or written down why you couldn't

A clean scan of your package-managed servers doesn't mean you're done if hand-installed PHP, managed hosting and appliances weren't part of it.

What to take away

Patch day isn't day zero. Someone was testing this exploit before the fix shipped, so don't assume nothing happened before 21 October.

The vulnerable bit can sit under a fully patched app. PHP lives below WordPress and below most SBOMs, which makes it easy to miss.

Big numbers aren't breach counts. Millions of exposed installs and high-profile shutdowns are serious, but neither tells you how many systems were actually compromised.

For teams in India, the practical step is to go after internet-facing PHP you're not sure about first, especially anything run by a third party or sitting on legacy hosting. For everyone, the investment worth making is being able to answer quickly: which PHP is serving this request, and what version was it running last Tuesday?


References

  1. PHP Group — security advisory and fixed releases (21 October 2026)
  2. AWS Threat Intelligence — MadPot pre-disclosure exploitation observation
  3. CERT-In — CIVN-2026-0510 (21 October 2026)
  4. Wiz — vulnerability analysis and research timeline
  5. Palo Alto Networks Unit 42 — potential exposure estimate
  6. Qualys Threat Research Unit — installation measurements, updated 22 October
  7. Reuters — reported international service interruptions
  8. Outage tracker — 56-entry crowdsourced snapshot, 22 October 15:52 UTC
  9. Cloudflare — WAF defenses and observed activity
  10. Dutch NCSC — operational guidance and backports
  11. NHS England — patch recommendations
  12. Canadian Cyber Centre — national advisory

Continue the conversation

See Transilience in thirty minutes

Book a thirty-minute walkthrough of Transilience — autonomous triage, compliance, and exposure workflows in one place. No pitch deck.

Share this post:

Related Posts