BreachDetect
← All posts

12 min read

PHP2Shell and the other big hacks of October 2026

A decade-old PHP bug took sites offline worldwide. Most of October's other breaches, from Railway to ASOS to Denmark's CPR register, began with a stolen login.

By BreachDetect Research

On Tuesday 20 October, details of two unpatched bugs in PHP started spreading on social media. By Wednesday afternoon the PHP team had shipped fixes, and governments were telling website owners to patch or take their sites down. Finland shut its public web services. The Dutch cyber security agency took its own website offline. In the UK, 32 government services went dark while updates went in, the cyber security minister, Liz Lloyd, told Parliament.

That was PHP2Shell, and it was the loudest security story of the month. It wasn't the only one. Since the start of October, a Python package that many AI teams depend on shipped with a password stealer inside, two hosting platforms had customer secrets read out of their databases, and someone pulled the names, addresses and ID numbers of 8.8 million people from Denmark's national register.

This is what happened, what's known as of 30 October, and what we'd do about it this week.

What is PHP2Shell?

PHP2Shell is the name for two critical vulnerabilities in the PHP engine itself, CVE-2026-109618 and CVE-2026-109619. Both score 9.2 on CVSS v4. They let an attacker with no account and no password run code on a web server, or read pieces of its memory.

PHP runs roughly 70% of websites, including WordPress, Drupal, Joomla, Magento and MediaWiki, the software behind Wikipedia. The flaw sits in PHP, not in any one app, so a plain "Hello World" page on an unpatched server is enough. Wiz, one of the two research teams that found it, says every PHP release back to 5.4 is hit by at least one of the bugs.

The PHP logo. PHP2Shell affects the PHP engine itself, so every site built on it was exposed.

How the bug works

In short, PHP cleans up badly when it runs out of memory halfway through reading a request.

PHP has a feature called session upload progress. It's on by default, and it starts tracking a file upload before your application code runs, even if your app never uses sessions. An attacker sends a large, carefully built upload that pushes PHP past its memory_limit at exactly the wrong moment. PHP aborts the request but leaves half-built internal data, and pointers to freed memory, behind. The next request on the same worker trips over that stale state. If the attacker controls what now sits in that memory, they control what PHP does next.

One variant sends memory back to the attacker inside a PHPSESSID cookie. Wiz showed this alone can expose passwords, session tokens, API keys and certificates belonging to other people's requests, with no code execution needed. Keep that in mind. It comes up again later.

Found by AI, leaked before the fix

Wiz and a second firm, Calif, found the bugs in August with help from frontier AI models. Wiz reported them to the PHP security team on 24 August. Its writeup is frank about what changed:

The underlying flaws had been present for decades, but demonstrating their exploitability required an exceptionally complex chain of steps, at the edge of what human researchers could practically achieve. Frontier AI models substantially reduced that barrier, turning a longstanding flaw into an exploit.

PHP had planned to publish later in the month. Then details leaked online on 20 October, a day before the patch was ready. Cloudflare saw thousands of exploit attempts in the ten hours before the official announcement, and Amazon says something probed its honeypots for the bug as early as 17 October.

How bad did it get?

Noisy at first. Then real.

Cloudflare's chief executive, Matthew Prince, said the company saw tens of thousands of attempts within 45 minutes of the announcement, hundreds of thousands within two hours, and "millions now" by the next day, The Guardian reported. Ciaran Martin, the former head of the UK's National Cyber Security Centre, called it "the most serious vulnerability discovered for five years". The NCSC sent 50,000 alerts to UK organizations.

For the first few days, most of that traffic was scanning and exploits that didn't work. That changed on 24 October, when Perplexity's Adel Karimi caught 35 working shells on honeypots running PHP 8.4.26 under Apache. CISA added both CVEs to its Known Exploited Vulnerabilities catalog on 26 October.

The worst case so far comes from Dream. Its researchers found a China-linked group chaining PHP2Shell with a Linux kernel bug to get root on Palo Alto Networks firewalls, which run PHP 8.0.30 on their management web server. The group rooted 25 servers across the US, Japan, Taiwan and South Korea. Inside one US government-affiliated network, it reached the server that manages every firewall the organization owns, decrypted an LDAP service account password, sprayed passwords at Active Directory and tried to create backdoor accounts. Palo Alto is shipping fixed PAN-OS versions.

Look at where that attack ended up. The firewall was the way in. The passwords were the point.

Patch, then deal with the follow-up bug

The fixed versions are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 and older are end of life and won't get a fix, so anything still on them needs an upgrade.

PHP has since disclosed a third, unpatched bug, CVE-2026-115560. It only affects apps with an unusual session setup, and the advice is the same setting that blunted the original attacks. Put it in php.ini or your FPM pool config, not in ini_set() or a .user.ini file, then restart every worker.

session.upload_progress.enabled = 0

To see whether someone already tried, these are the log lines Datadog Security Labs suggests hunting for. Log paths vary by distro.

# PHP ran out of memory before any script started, often followed by a broken session
grep -E "exhausted.*in Unknown on line 0|Failed to decode session object" /var/log/php*.log

# PHP-FPM workers crashing
grep "exited on signal 11" /var/log/php*-fpm.log

A normal out-of-memory error names a script and a line number. One that says in Unknown on line 0 happened before your code ran, which is rare by itself. Also look for PHP worker processes like php-fpm or apache2 starting sh, bash, curl or wget. A healthy web server has no reason to do that.

LiteLLM shipped a credential stealer

On the same Wednesday PHP released its fix, LiteLLM version 1.107.0 went out on PyPI and Docker Hub with malware inside. LiteLLM is an open source proxy that teams use to route requests to OpenAI, Anthropic and other model providers, so the machines running it tend to hold a lot of API keys.

The bad release was built from a lookalike GitHub repository, Berri-AI/litellm. It was live on PyPI from 11:39 to 13:23 UTC on 21 October, and the Docker images stayed compromised until 14:20 UTC. It installed a file called cook.pth that runs every time Python starts, so nobody had to import LiteLLM for it to fire. According to the maintainers' security issue and Microsoft's analysis, it collected:

  • saved passwords and cookies from Chromium-based browsers and Firefox
  • SSH keys and shell history
  • AWS, Azure and Google Cloud credentials, including the role tokens of the cloud machine it ran on
  • .env files, Git credentials, and npm and PyPI tokens
  • config files and tokens for AI coding tools such as Claude, Cursor, Codex and Copilot
  • every model provider key stored in the LiteLLM proxy's own database

That's close to what commodity infostealers like RedLine and Lumma take from a home PC. This one ran on build servers and developer laptops, where the logins lead to production.

If 1.107.0 ever ran on a machine with internet access, the maintainers say to assume the data left. Don't pip install over it, because every Python start runs the payload again. Delete the startup files, rebuild the environment, pin litellm==1.106.2 and rotate everything that machine could reach.

Railway and Zeabur: customer secrets read out of the platform

Two app hosting platforms disclosed breaches within days of each other. Both ended with customers rotating every secret they'd stored.

Railway

Railway spotted an attacker on 20 October and confirmed they were out early on 22 October. In its preliminary report, Railway says the attacker reached its CI environment and used credentials from there to decrypt stored environment variables. Up to 1.85% of workspaces, about 100,000, may be affected. The attacker was hunting for AI provider API keys "to perform distillation attacks". Railway asked GitHub, GitLab, Anthropic, OpenAI, OpenRouter, Stripe and others to revoke keys before it went public, and it now tells everyone who signed up before 21 October to rotate.

Zeabur

Zeabur, a smaller deployment platform, was breached on 14 and 15 October. Its incident report is unusually blunt. The attacker used leaked internal credentials. Admin tokens and AWS keys sat in plaintext in a private config repository, never expired, and worked against an admin interface open to the internet. With them, the attacker read 3,218,965 environment variable records tied to 321,810 accounts, logged in as root on 101 servers and ran commands against 865 customer database services. Some of those credentials had survived the cleanup after an earlier breach in August.

Zeabur has since announced it is shutting down. Everything goes offline by 31 December.

The rest of October's breaches

PHP2Shell got the headlines. The breaches that actually exposed people's data mostly started somewhere far more ordinary.

IncidentDisclosedScaleHow they got in
Denmark's CPR register5 OctAbout 8.8 million peopleA small firm's legitimate lookup access. A hacker claims a former employee's leaked password
ASOS6 OctPotentially millions of customers, per the BBCAn employee was tricked into handing over a login
Arizona court system7 Oct1.3 million peopleReportedly, an employee clicked a malicious email link
Burger King Japan16 Oct11.18 million recordsNot disclosed
ETS, California student data16 OctNo official countOne compromised login to a file transfer server, used from May to September
CenterPoint Energy16 Oct1,062,060 TexansNot disclosed
Zeabur19 Oct321,810 accountsLeaked internal admin credentials
Railway21 OctAbout 100,000 workspacesNot yet disclosed, attacker was after AI keys
So-net, Sony Network Communications27 OctAbout 2.59 million member recordsUnder investigation

Denmark: 8.8 million people and a password of 123456

Nothing in the Danish case was technically broken into. Pays ApS, a two-person software company in Odense, had a legal right to look people up in the CPR register. Between 10 and 20 September, someone used that access to run about 14 million lookups and pull names, addresses and CPR numbers for 8.8 million people. The register holds about 11 million records in total, including people who have died or emigrated. Denmark's civil protection agency now says a CPR number can no longer be relied on to prove who someone is.

Security monitoring didn't catch it. The CPR office noticed on 2 October, almost two weeks after the lookups stopped, because the bill for them was absurdly large. An anonymous hacker later told the newspaper Politiken they logged in with a former employee's leaked password, 123456. That claim isn't confirmed. As CSIS points out, if it's true, one of the largest data leaks in Danish history came down to an account nobody switched off, protected by one of the most common passwords in the world.

ASOS: one employee, one login

ASOS app users got a push notification on 6 October titled "ASOS hacked", with a link to Telegram. ASOS later confirmed that someone impersonated a trusted contact to get an employee's login, then used it on third-party platforms ASOS relies on. The BBC found the stolen data went further than the "basic contact details" ASOS first described. It includes names, addresses, phone numbers, dates of birth and what customers searched for on the site. ASOS says no passwords or card numbers were taken. The group behind it claimed it got in through a service built on Snowflake.

What October says about where attacks start

Strip out the AI angle and the CVE numbers and the month looks familiar. Attackers want logins. Sometimes they get them by breaking a server. Sometimes they plant a stealer in a package, or talk an employee into handing one over. And sometimes a former employee's 123456 still works.

PHP2Shell fits that pattern more than it seems to at first. The memory leak variant hands over passwords and tokens. The firewall intrusions went straight for Active Directory. Railway's attacker wanted API keys, and LiteLLM's payload harvested browser logins and cloud keys from developers' machines, which is exactly how stealer logs get made.

Patching is the first step, not the last. If a server, laptop or CI runner was exposed this month, assume some credentials left with the attacker, and plan for them to turn up later. Stolen logins are rarely used the day they're taken. They get sorted, sold and passed around in stealer logs and breach dumps for months or years, until someone tries them against your VPN, your Microsoft 365 tenant or your admin panel.

A checklist for the next two weeks

  1. Find every PHP install you run, including the ones inside vendor products like firewalls, NAS boxes and hosting control panels. The Dutch NCSC keeps a list of affected third-party software.
  2. Update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35. Anything on 8.1 or older comes off the internet until it's upgraded.
  3. Set session.upload_progress.enabled = 0 until PHP ships a fix for CVE-2026-115560.
  4. Check your logs for the signs above, and for PHP workers starting shells. If you find them, treat the server as compromised and rebuild it.
  5. Search every Python environment and container image for litellm==1.107.0 and for a stray cook.pth in site-packages.
  6. If you host on Railway or Zeabur, rotate every secret stored there at the service that issued it, not only in the dashboard.
  7. Rotate any password, token or key that lived on an exposed machine, and force sign-outs so stolen session cookies stop working.
  8. Disable accounts for people who have left. Denmark is the reminder nobody wanted.
  9. Watch for your company's logins turning up in stealer logs and breach dumps over the next few months, because some of them will.

The last item is the one we built BreachDetect for. We index stealer logs and breached databases, billions of records of them, and tell security teams when a login tied to their domain shows up. If you want to know where you stand after a month like this one, you can check your company domain for free. It takes a few seconds and you don't need an account.

Quick answers

Is my WordPress site affected by PHP2Shell?

If it runs on a PHP version older than 8.5.12, 8.4.27, 8.3.36 or 8.2.35, yes. The bug is in PHP, not WordPress, so updating WordPress or its plugins won't fix it. If someone else hosts your site, check the PHP version in your hosting dashboard rather than assuming they've patched.

Has anyone actually been hacked through PHP2Shell?

Yes. Honeypots recorded working shells from 24 October, CISA lists both CVEs as exploited, and Dream documented 25 servers rooted through Palo Alto firewalls. Most traffic is still automated scanning, but the Delft Threat Intelligence Lab had logged more than 74,000 exploit requests from 677 IP addresses by 29 October, and 177 of those addresses tried to run code.

I patched. Am I done?

Not quite. Patching closes the hole but doesn't undo anything that happened before. Check for signs of compromise, and rotate credentials on any server that was exposed and unpatched after 20 October.

We'll update this post as the PHP2Shell, Railway and Zeabur investigations progress.

See what has already leaked from your company.

Search your domain across stealer logs and breached databases. Free, no account needed.