"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."
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.
longjmp()interrupts the parser mid-flight.- The shutdown routine takes over and assumes the partially initialized internal structures are valid pointers.
- 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:
- Request A poisons and frees the memory.
- 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 diffon the C source code, reverse-engineered the exactlongjmp()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] = -1in your FPM pool or Apache config so an attacker cannot intentionally trigger the userlandmemory_limitlongjmp()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 clamppost_max_sizedown to8Mat your Nginx/reverse-proxy layer. - To blunt CVE-2026-109619 (Stale State): Set
session.upload_progress.enabled = 0and (on PHP 8.5)fatal_error_backtraces = 0directly inphp.ini—not viaini_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.