October 22, 2026
When the Prime Minister of Japan Told Websites to Go Offline and My Tech Lead Froze Deployments…
“No deployments for the next 10 days. Everything is frozen.”
By karnVen
7 min read
That was the WhatsApp message from my tech lead yesterday.
As a PHP developer working with Laravel and Drupal in our company, my day-to-day rhythm is straightforward: build new features, polish the UI/UX, document the changes, and hand off release notes to our server team to pull live directly into our company's on-premise local server.
When my senior dropped that message into our team chat, I was genuinely baffled. I asked if our CI pipeline broke, if our on-premise rack had a power surge, or if we had hit some nasty dependency conflict.
His reply was short: "Search PHP news today. Major core zero-day."
At first, I assumed it was just another package bug or framework vulnerability-the kind where you run composer update, bump a patch version, run tests locally, and move on.
Then I started reading the security advisories and international news, and the scale of it hit me.
It wasn't a package issue. It wasn't even a framework bug.
It was PHP2Shell (CVE-2026–109618 & CVE-2026–109619)-a CVSS 9.2 Critical pre-authentication Remote Code Execution vulnerability sitting directly inside the C Zend Engine that powers approximately 70% of the entire web.
The International Alarm: An "Update or Shut Down" Directive from Tokyo
While I was staring at my terminal, governments across the world were already mobilizing.
In Tokyo, Japan's Prime Minister Sanae Takaichi took to public channels late Wednesday evening through the National center of Incident readiness and Strategy for Cybersecurity (NISC) with an unprecedented national emergency order: all public-facing infrastructure running PHP must apply security patches immediately, or proactively take services offline.
Japan's Prime Minister Sanae Takaichi issued a nationwide directive ordering public and private infrastructure running PHP to update or take servers offline.
To show the severity of the threat, government portals and even the Prime Minister's personal official website were temporarily taken down for security auditing and runtime verification. Across Japan, major financial institutions and online platforms-including MUFG Bank, Mizuho, Japan Post Bank, and the digital media platform Niconico-instituted emergency maintenance windows to isolate their PHP backends.
Across the globe, the United States Cybersecurity and Infrastructure Security Agency (CISA) added CVE-2026–109618 to its Known Exploited Vulnerabilities (KEV) catalog with an urgent federal binding operational directive. Meanwhile, France's ANSSI and Germany's BSI released critical notices warning that automated botnets were actively scanning IPv4 address space for vulnerable PHP endpoints.
The Technical Deep Dive: What Actually Breaks in the C Zend Engine?
To understand why this vulnerability has sent shockwaves through the engineering community, you have to look past Laravel and Drupal and look straight into native C.
It Strikes Before Your Application Even Boots
In a modern PHP stack (like Laravel or Drupal served by Nginx and PHP-FPM), your application code does not wake up the moment an HTTP packet arrives.
Before Laravel's public/index.php or Drupal's bootstrap routines ever execute, PHP's Server API (SAPI) layer parses raw HTTP POST bodies, multipart/form-data boundaries, and query strings in native C.
Because PHP2Shell exploits the memory routines during this initial C-level parsing phase:
- Your route middleware never runs.
- Form request validation rules never evaluate.
- CSRF protection and authentication guards are completely bypassed.
The attacker controls the machine before your PHP code even knows a request exists.
The Race Condition in Zend/zend_hash.c
At the center of the PHP runtime is the Zend HashTable-the underlying C data structure that powers associative arrays, global symbol tables, and parsed request parameters.
Here is the vulnerable logic path inside the Zend Engine:
Notice the critical ordering flaw: ht->nNumUsed++ increments the counter before confirming that memory allocation succeeds.
The Panic: zend_bailout() and longjmp()
When a server handles an incoming request, PHP enforces the memory_limit configured in php.ini (e.g., 128M or 256M).
When an attacker sends a crafted multipart HTTP request with deeply nested boundaries or bloated headers, zend_hash_do_resize() attempts to allocate more memory and hits memory_limit.
When PHP hits this wall, it does not throw a catchable PHP exception, nor does it perform clean C++ RAII object destruction. Instead, it triggers zend_bailout().
Under the hood, zend_bailout() uses the standard C library function longjmp():
The longjmp() function instantly unwinds the C call stack. It jumps straight out of the parsing routine, skipping all cleanup logic for the partially initialized HashTable bucket. The count ht->nNumUsed was already incremented, but the bucket it points to is left filled with uninitialized heap garbage.
The Attack Surface: PHP-FPM Persistent Workers
If PHP ran exclusively as a command-line script (CLI), the operating system would wipe the entire process memory space when the process terminated.
However, in high-performance production environments running Nginx with PHP-FPM, worker processes stay alive across hundreds of consecutive requests ( pm.max_requests = 500) to avoid process fork overhead.
When a worker survives a longjmp bailout:
- The corrupted HashTable remains in the persistent worker process memory.
- During request termination,
php_request_shutdown()traverses the HashTable to free resources, dereferencing the uninitialized bucket pointer. - By grooming the heap with previous multipart chunks, the attacker controls the address stored in that pointer, steering execution directly into arbitrary shellcode (Pre-Authentication Remote Code Execution).
The Non-Technical Explanation: The Hotel Receptionist, Fire Alarm, and Cleaning Crew
If C pointer mechanics and memory offsets feel like a blur, here is an everyday analogy for how this vulnerability works in the real world:
Imagine a busy 5-star hotel lobby:
1. The Receptionist (PHP-FPM Worker):
To keep check-ins moving fast, the receptionist doesn't get replaced after every guest. They stay at the front desk all day, greeting hundreds of visitors back-to-back.
2. The Hotel Ledger (Zend HashTable):
Whenever a guest checks in, the receptionist writes their room number and luggage tag into the front desk ledger.
- The Luggage Room Limit (
memory_limit):
The hotel has a strict rule: all luggage checked in for a single visit must fit into a designated storage room.
- The Malicious Guest & The Fire Alarm (
zend_bailout):
An intruder walks in carrying an enormous, strangely shaped tower of suitcases designed to fill the luggage room to the absolute ceiling. As the receptionist begins writing the ticket number in the ledger, the luggage room hits maximum capacity and a deafening fire alarm sounds.
- The Fire Escape (
longjmp):
In an emergency, the hotel protocol is absolute: drop everything and run out the fire escape immediately. The receptionist doesn't finish writing the room number, doesn't verify the baggage claim tag, and doesn't lock the luggage cabinet.
6. The Cleaning Crew (Request Shutdown):
Once the alarm resets, the receptionist returns to the desk to greet the next customer. The cleaning crew steps in to tidy up from the previous guest. They open the ledger, see a half-written entry pointing to an unchecked locker, and blindly open whatever bag is tagged there.
Inside that bag isn't guest clothing-it's the intruder's remote control, handing complete control of the hotel over to the attacker.
The AI Revelation: How a 20-Year-Old Bug Was Finally Found
Perhaps the most astonishing aspect of PHP2Shell is its origin story.
As reported by Reuters, this flaw lived silently inside the C Zend Engine codebase for over two decades. Human security researchers, core PHP maintainers, and commercial penetration testers had audited those exact C files thousands of times and missed it.
Why did humans miss it? Because reproducing it required an extraordinary combination of edge cases:
- Hitting an exact memory boundary during HashTable bucket resizing.
- Intercepting the memory limit abort right at the point where
ht->nNumUsedhad been incremented but the memory block was not yet mapped. - Tracking how persistent PHP-FPM process reuse preserved that tainted memory state across request lifecycles.
It was discovered using modern AI-assisted semantic fuzzing models capable of reasoning across asynchronous C call stacks and simulating memory states through longjmp control transfers. Where human auditors saw standard boundary checks, AI reasoning models connected the state discrepancies across worker lifecycles.
The Fix: What Every DevOps Team Needs to Do Right Now
The PHP core security team responded with emergency patched releases:
(Note: Older branches like PHP 7.4, 8.0, and 8.1 are officially End-of-Life and do not receive upstream security patches).
The Critical Mistake Many Admins Make
Running apt update && apt upgrade or updating your binary on disk does not fix the running vulnerability in RAM.
Because PHP-FPM workers stay loaded in memory, existing vulnerable workers will continue serving traffic until you explicitly restart the service:
# Restart PHP-FPM and your web server immediately sudo systemctl restart php8.2-fpm # Replace with your installed version sudo systemctl restart nginx# Restart PHP-FPM and your web server immediately sudo systemctl restart php8.2-fpm # Replace with your installed version sudo systemctl restart nginxIf your application runs inside Docker containers, rebuild without using cached layers:
docker compose build --no-cache docker compose up -d --force-recreatedocker compose build --no-cache docker compose up -d --force-recreateGuided Resources: Where to Go Deep
Rather than leaving you with a list of random links, here are curated guides and video walkthroughs to help you master these concepts:
Video Walkthroughs
If you want to see how the Zend Engine organizes hash tables, zvals, and memory in native C, watch this visual breakdown:
This video explains PHP's internal memory allocator, reference counting, and why low-level pointer management makes PHP so fast.
To understand how PHP-FPM manages persistent worker pools, process lifecycle recycling, and request handling behind Nginx, this architecture walkthrough is essential:
Learn how worker processes are spawned, how requests are passed through UNIX sockets, and why worker persistence introduces unique security considerations.
If you want a step-by-step demonstration of memory corruption, heap grooming, and how low-level pointer redirection works in modern exploitation:
A practical guide to understanding buffer boundaries, return-oriented programming concepts, and memory security.
Official Advisories and Technical Papers
If you need to verify CVE details or review the upstream patches:
Looking Back: Lessons From the Sidelines
Where does all of this leave a developer like me?
Honestly, on the sidelines for now. I've been working with PHP, Laravel, and Drupal in real-time production environments for about seven months. Touching core C runtimes, tuning kernel sockets, and patching production server clusters is senior DevOps territory. Our infrastructure leads are managing the upgrades and regression tests.
My deployments may be frozen for the next 10 days, but instead of treating it as downtime, I used the pause to understand what is actually happening beneath my PHP code.
Sometimes the biggest breakthroughs in your career happen when you stop building features for a moment and look down into the engine powering everything.
Has your team frozen deployments or restarted your PHP-FPM clusters yet? Let's discuss in the comments below.
Originally published at https://dev.to on October 22, 2026.