Writing

"Update PHP or Unplug the Server": How GPT-5.6 and Gemini 4 Just Weaponized a 14-Year-Old Bug into PHP2Shell

Wikipedia and the Internet Archive went dark before the patch even dropped. Inside PHP2Shell (CVE-2026-109618 & CVE-2026-109619)—the pre-auth RCE that proves AI models don't care if maintainers think a bug is "unexploitable."

PHPCybersecurityZero-DayAI SecurityGPT-5.6 SolGemini 4 ArgonVulnerabilityTech News
A terminal session showing the PHP2Shell memory corruption trigger alongside emergency server shutdown notices.

On Tuesday, the FBI, the NSA, and the Prime Minister of Japan all effectively gave sysadmins the same piece of architecture advice: patch PHP at 14:00 UTC on Wednesday, or yank the ethernet cable out of the wall.

Before the official patch even landed, the Internet Archive pulled its servers offline. Wikimedia killed its Phabricator instance. Across Europe, government portals in Finland, France, and Germany went dark alongside pieces of the BBC, 4chan, and DeviantArt.

Why? Because of two vulnerabilities now dubbed PHP2Shell (CVE-2026-109618 and CVE-2026-109619).

They carry a 9.2 CVSS score from the PHP Foundation—and a flat 10.0 from researchers at watchTowr. They affect every version of PHP from 5.4 through 8.5.11. They require zero authentication. And here is the kicker that had infrastructure teams sweating through their shirts on Wednesday morning: the exploit triggers before a single line of your application code even runs.

Your clean Laravel controllers won’t save you. Your hardened WordPress plugins don’t matter. If your server parses an incoming HTTP request using PHP—whether through mod_php, PHP-FPM, php-cgi, LiteSpeed, or FrankenPHP—you are in the blast radius.

And how did we find a 14-year-old dual memory-corruption flaw hiding in the core C engine of nearly 75% of the web?

Frontier AI models found it. And then the humans handling the disclosure fumbled the embargo so badly that attackers had the receipts before you had the binary.

The Part They Hope You Skim: A 2024 “Non-Issue” Meets 2026 LLMs

Let’s look at the origin story, because it says everything about where software security actually stands right now.

Concerns about PHP’s internal memory safety during request teardown have been whispered about for over a decade. In fact, a PHP core developer spotted the exact out-of-memory (OOM) condition behind CVE-2026-109618 during a manual audit back in 2024.

Nothing was done. Why? Because the core team couldn’t agree on a clean fix, and more importantly, nobody thought writing a reliable exploit for it was humanly feasible.

In 2024, “too complex to exploit reliably” was a valid triage status. In 2026, it is a death sentence.

In August 2026, two groups independently fed the PHP C codebase into frontier models:

  • Ryan Austin at California security firm Calif—operating under OpenAI’s glossy “Patch the Planet” initiative—used GPT-5.6 Sol to hunt down and weaponize the path.
  • Wiz Research (now sitting under Google Cloud) paired Gemini 4 Argon and GPT-5.6 Sol with their internal Wiz Atlas engine to uncover the exact same primitives.

What a room full of senior C maintainers wrote off as an unexploitable edge case in 2024 took next-gen reasoning models a couple of summer weeks to turn into deterministic, pre-auth Remote Code Execution.

Under the Hood: How PHP2Shell Hijacks the Worker Before index.php

PHP2Shell isn’t a single bug; it’s a two-headed monster inside the Zend Engine’s request lifecycle. Both flaws abuse a fundamental assumption in how PHP handles errors and cleans up after itself.

1. CVE-2026-109618: The longjmp() OOM Trap

When a PHP script exceeds its configured memory_limit, the engine doesn’t politely unwind the stack. It uses C’s longjmp() to violently abort the request and jump straight to the shutdown/cleanup routine.

Here is the fatal flaw: an attacker can send a carefully crafted, unauthenticated request—for example, a malformed multipart form upload—that deliberately trips the memory_limit while PHP is still parsing the raw HTTP request, before internal request structures are fully initialized.

  1. longjmp() interrupts the parser mid-flight.
  2. The shutdown routine takes over and assumes the partially initialized internal structures are valid pointers.
  3. PHP calls free() on uninitialized memory—memory that still holds leftover heap data from previous requests controlled by the attacker.

You get an arbitrary free() primitive before your index.php is even loaded into memory.

2. CVE-2026-109619: Stale Worker Poisoning (Use-After-Free)

Unless you are running CGI like it’s 1998, your PHP workers (PHP-FPM children or Apache mod_php threads) handle thousands of requests in a loop.

Under CVE-2026-109619, if a request triggers a specific fatal error or bailout (for instance, abusing session.upload_progress or PHP 8.5’s fatal_error_backtraces), internal global state owned by that request survives after its backing memory has been freed.

When the next request hits that same worker process, PHP reads and branches on that dangling pointer before normal request initialization resets it:

  1. Request A poisons and frees the memory.
  2. Request B triggers the Use-After-Free and hands the attacker a shell running with the privileges of the web worker.

The Embargo Collapse: A Masterclass in Chaos

If the technical bug is terrifying, the disclosure timeline is pure comedy.

The PHP Foundation originally tried to do the responsible thing: announce on October 20 that a critical patch was dropping on Wednesday, October 21 at 14:00 UTC, giving sysadmins a 24-hour heads-up to clear their calendars without revealing the bug.

Then the embargo disintegrated in real time:

  • The Leaked PoC Video: Calif—the very firm that discovered the bug under OpenAI’s project—accidentally published a video of the working proof-of-concept exploit early.
  • The Chainguard Patch Diff: Container platform Chainguard pushed patched images before the embargo lifted. Every exploit developer on earth immediately ran git diff on the C source code, reverse-engineered the exact longjmp() and session state fixes, and built working weaponized payloads before the official PHP release even went live.
  • Pre-Disclosure Exploitation: Amazon Threat Intelligence reported seeing PHP2Shell exploitation attempts in its MadPot telemetry dating back to October 17—four days before the patch existed.

By the time the PHP team scrambled to push the advisories out 26 minutes early on Wednesday, the sharks were already circling. Security firm Sansec warned that mass automated scanning would start within 15 minutes of release. watchTowr’s honeypots lit up almost immediately.

What You Should Actually Do Right Now

Stop reading vendor blog posts telling you that a Web Application Firewall (WAF) has you covered. Cloudflare and Google Cloud Armor pushed emergency rules to block oversized multipart payloads, and while that buys you twenty minutes of breathing room, a WAF cannot reliably patch a C-level heap corruption bug. Attackers can fragment requests, omit Content-Length headers, or chain tiny allocations to hit the exact same OOM cliff.

Here is your actual engineering checklist:

1. Patch the Binary Immediately

Upgrade to PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35. Rebuild your Docker base images (php:8.x-fpm) and redeploy your Cloud Run / ECS tasks. Do not assume your cloud provider auto-patched your flexible containers.

2. If You’re Stuck on PHP 8.1 or 7.x

The upstream PHP project is not releasing official binaries for 8.1 or older because they are End-of-Life. Either rely on backported OS distro patches (Ubuntu/RHEL/Debian are scrambling these out now) or apply the emergency config workarounds below while you plan a weekend migration.

3. Emergency Band-Aids (If You Can’t Patch for 6 Hours)

  • To blunt CVE-2026-109618 (OOM): Counter-intuitively, set php_admin_value[memory_limit] = -1 in your FPM pool or Apache config so an attacker cannot intentionally trigger the userland memory_limit longjmp() bailout. Then enforce strict memory limits at the container/cgroup level (so the OS OOM-killer kills the whole worker process instead of letting PHP run its corrupted cleanup) and clamp post_max_size down to 8M at your Nginx/reverse-proxy layer.
  • To blunt CVE-2026-109619 (Stale State): Set session.upload_progress.enabled = 0 and (on PHP 8.5) fatal_error_backtraces = 0 directly in php.ini—not via ini_set() or .user.ini, which run too late in the request lifecycle. Then restart every worker.

4. Assume Breach & Check Worker Persistence

Patching closes the door; it doesn’t evict the squatter. Because this exploit executes in the worker context before app logging kicks in, your standard application logs won’t show the breach. Audit outbound network connections from your web nodes, check /tmp and /dev/shm for unexpected binaries, and rotate every secret sitting in your PHP environment variables (phpinfo() is always the first thing dumped).

My Honest Take

For the last six months, frontier AI labs have been putting out cinematic press releases about how their cyber-capable models are going to “Patch the Planet” and usher in a golden age of defensive security.

PHP2Shell is what “Patch the Planet” actually looks like when it hits the real world.

Yes, GPT-5.6 Sol and Gemini 4 Argon found a catastrophic 14-year-old bug that human maintainers shrugged off. That is a genuine engineering milestone.

But here is the cold reality: AI has completely killed the “too hard to exploit” buffer that kept legacy open-source software standing. For thirty years, the internet survived because C codebases like PHP, OpenSSL, and the Linux kernel were only audited as fast as exhausted humans could read pointer arithmetic. Now, models can synthesize multi-stage heap grooming and longjmp() corruption chains while you sleep.

Meanwhile, our human patching pipeline—embargoes, leaked PoC videos, premature container commits, and millions of unmaintained PHP 7.4 servers—is still stuck in 2014. We have automated zero-day discovery at frontier scale, and paired it with a distribution system that requires Wikipedia to literally turn itself off to survive a Wednesday afternoon.

Go check your php -v. And if your staging server is still running PHP 8.1, cancel your weekend plans.