All posts

4 min readSecurity

PHP2Shell Explained: The PHP Bug That Hit 70% of the Web

Two bugs inside PHP itself let strangers run code on your server. Here is what PHP2Shell is, how it works, and how to fix it.

  • #php
  • #security
  • #cve
  • #wordpress
  • #ai

PHP2Shell Explained: The PHP Bug That Hit 70% of the Web

PHP runs about 70% of all websites. In October 2026, two serious bugs were found in PHP itself. Not in a plugin, not in a framework, but in the language.

If you run anything on PHP, update it today. Here's what happened, in plain words.

What is PHP2Shell?

PHP2Shell is the name for two bugs in PHP's core engine:

  • CVE-2026-109618
  • CVE-2026-109619

Both are rated 9.2 out of 10. That's critical.

With them, a stranger on the internet can:

  • Run their own code on your server. No login needed.
  • Read secrets from memory. Passwords, API keys, tokens and cookies from other people's requests.

The scary part: the bug is in PHP, not in your code. WordPress, Drupal, Joomla, or a tiny "Hello World" page. If it runs on a vulnerable PHP version, it's exposed.

Almost every PHP version from the last 10+ years is affected, all the way back to PHP 5.4.

How does it work?

PHP itself is written in C, but you don't need to know any C to follow this. Here's the simple version.

1. PHP reuses its workers. A PHP server keeps a few workers alive. Each worker handles one request, then picks up the next one. This is fast, because nothing has to start from scratch.

2. Every request should clean up after itself. When a request ends, PHP throws away its memory so the next request starts fresh.

3. A crash skips the cleanup. An attacker sends a request that makes PHP run out of memory halfway through. PHP stops in a hurry. It frees the memory, but it forgets to clear a few notes that still point to it.

4. The next request trusts those notes. The worker picks up a new request. PHP sees the old notes and thinks they're still valid. But that memory now holds something else, and the attacker can control what goes there.

Think of a hotel room. The last guest leaves in a rush, and nobody checks the room. The next guest finds the old room key and a note saying "the safe code is 1234". Except the safe now belongs to someone else.

That's the whole hole: leftovers from one request leak into the next. From there, an attacker can read memory they shouldn't see, or trick PHP into running their code.

Why now, after 10 years?

The bug was there for over a decade. Turning it into a real attack was very hard. You had to chain several steps and guess exactly how memory was laid out on each server.

This time, researchers used AI models to help. Work that would have taken a team months took about a week. That's the real lesson: "too hard to exploit" doesn't protect old bugs anymore.

How was it fixed?

The PHP team shipped fixed versions on October 21, 2026. The fix makes PHP fully clean up its state when a request crashes, so nothing stale survives into the next one.

Your branchUpdate to at least
PHP 8.58.5.12
PHP 8.48.4.27
PHP 8.38.3.36
PHP 8.28.2.35

PHP 8.1 and older are past end of life, so they get no official update. If you're still on one of them, now's the time to move up.

What should you do?

Step 1: Check your version

php -v

If the number is lower than the table above, you're vulnerable.

On Docker, check inside the container:

docker compose exec app php -v

Swap app for your service name.

Step 2: Update PHP

On Ubuntu or Debian, upgrade the PHP packages for your version:

sudo apt update
sudo apt install --only-upgrade 'php8.3*'

On Docker, pull the latest image for your tag and rebuild:

docker compose pull
docker compose build --pull
docker compose up -d

Tags like php:8.4-fpm or wordpress:latest move to the fixed version. Pinned tags like php:8.4.26 don't, so bump them by hand.

On shared hosting, check your host's dashboard or ask support. Most of them patch PHP for you.

Step 3: Restart PHP

The old, buggy code stays in memory until the workers restart:

sudo systemctl restart php8.3-fpm
# or, if you use Apache with mod_php
sudo systemctl restart apache2

Can't update today?

You can lower the risk for now. Add these to your php.ini (or your PHP-FPM pool config), then restart:

session.upload_progress.enabled = 0
memory_limit = -1
  • session.upload_progress.enabled = 0 turns off a feature that several of the attacks use.
  • memory_limit = -1 stops PHP from hitting its own memory limit, which is what starts the crash. Put a memory limit on the container or server instead, so one bad request can't eat the whole machine.

Put these in php.ini, not .user.ini or ini_set(). Those load too late to help.

This is a seatbelt, not a fix. Update as soon as you can.

Things to watch out for

  • Restart every worker. Updating the package isn't enough while old workers are still running.
  • Check every server. Staging boxes, old side projects and forgotten cron servers count too.
  • PHP 8.2 ends soon. It reaches end of life on December 31, 2026. Plan your upgrade.
  • Watch your logs. Lots of memory-limit errors or sudden bursts of HTTP 500s can be a sign that someone is trying this.

That's it

PHP2Shell is a bug in PHP itself, so every PHP site is in scope. Check php -v, update to a fixed version, and restart. The official details are on php.net.

Share this post