Cybersecurity

Apache HTTP/2 CVE-2026-23918: A Two-Frame Double-Free That Takes Down Half the World's Web Servers — and a Practical Path to RCE

2026.05.29 · 36 views
Apache HTTP/2 CVE-2026-23918: A Two-Frame Double-Free That Takes Down Half the World's Web Servers — and a Practical Path to RCE

Why one TCP connection and two frames are enough to crash mod_http2, why the scoreboard makes the RCE path realistic, and the 60-minute hardening you should run before Monday

On May 27 2026, Apache published the fix for CVE-2026-23918, a critical (CVSS 8.8) double-free in mod_http2 that affects Apache HTTP Server 2.4.66 and is patched in 2.4.67. The bug is exploitable unauthenticated, over a single TCP connection, with two HTTP/2 frames, against any default configuration that enables HTTP/2 — which is the majority of public Apache installations. The DoS path is trivial. The remote-code-execution path is not theoretical: researchers Bartlomiej Dmitruk (Striga.ai) and Stanislaw Strzalkowski (ISEC.pl) demonstrated a stable RCE chain using Apache's scoreboard memory as a fixed anchor. If you operate any internet-facing Apache, this is the highest-priority patch of the week, and probably the quarter.


1. What breaks, in three sentences


When a client sends an HTTP/2 HEADERS frame immediately followed by a RST_STREAM frame with a non-zero error code on the same stream — before the multiplexer has registered that stream — two nghttp2 callbacks fire in sequence: on_frame_recv_cb for the reset, then on_stream_close_cb for the close. Both call h2_mplx_c1_client_rst, which calls m_stream_cleanup, which pushes the same h2_stream pointer onto the spurge cleanup array twice. Later, c1_purge_streams iterates the array and calls h2_stream_destroy on each entry, freeing the same memory twice.


2. Why the RCE path is realistic, not theoretical


The classic objection to a double-free RCE chain is "ASLR makes the freed pointer unpredictable." Apache breaks that defence in a subtle way. The Apache scoreboard — the shared-memory segment that mod_status and worker processes use to track per-worker state — is allocated at a fixed virtual address at server startup, and that address survives the lifetime of the parent process even when ASLR is enabled. Attackers can place a forged h2_stream struct in scoreboard memory, point its pool cleanup function to system(), prime the freed slot with mmap reuse, and use the scoreboard as a stable container for both the fake structures and the command string. The result is a deterministic RCE on a vanilla Apache build with default hardening.


This is the cleanest worked example we have seen of an "ASLR doesn't save you when there's a fixed shared-memory region" RCE since the 2018 nginx mp4 module work. Expect public exploits to land within days, if they have not already on private channels.


3. The 60-minute hardening you should run before Monday


Minute 0–10: patch or downgrade HTTP/2. Upgrade to Apache 2.4.67. If you cannot patch in the next few hours, disable HTTP/2 at the vhost level (Protocols http/1.1) and reload. You will lose HTTP/2 performance; you will keep your server. Patch later in the day.


Minute 10–25: scan and inventory. Identify every Apache instance on your perimeter. If you self-host: nmap -p 443 --script http2-info against your perimeter ranges. If you have many sites behind a CDN, the CDN usually terminates HTTP/2 — confirm the origin Apache is not directly exposed. The instances most at risk are the ones you forgot you had: a staging server, a legacy admin panel, a vendor portal someone stood up in 2019.


Minute 25–40: enable mod_security with the OWASP CRS HTTP/2 rules. The 4.7 release of the OWASP Core Rule Set includes a heuristic that detects the specific HEADERS-then-RST sequence pattern. It is not a complete mitigation but it raises the cost of probing substantially and gives you log entries you can alert on.


Minute 40–55: alert on the crash signature. The DoS trigger leaves an unmistakeable trace in the Apache error log — repeated worker segfaults with HTTP/2 stream IDs. Add a high-priority alert. If you see it, treat it as an active exploitation attempt and rotate any secret that may have been in process memory.


Minute 55–60: write the post-mortem note. Even if you patched cleanly, write a one-paragraph summary of "we ran 2.4.66, exposure window, what we did" for your security stakeholders. It is the cheapest insurance against later questioning.


4. What this means for the Apache-vs-NGINX conversation


Three CVEs in one month — NGINX Rift (May 17), this Apache HTTP/2 flaw (May 27), Gitea container-image bypass (May 27) — have all been in widely deployed self-hosted infrastructure with deep root-cause: legacy code paths, fixed memory regions, missing authorization checks at a secondary access path. The conclusion is not "switch web servers." It is that any self-hosted edge infrastructure in 2026 needs an owner whose job is to read the disclosure feed and act within 24 hours, regardless of whether they run NGINX, Apache, Caddy, or Traefik. The teams that take Apache 2.4.67 to production this weekend look the same as the teams that took NGINX 1.30.1 to production two weeks ago: they are the teams that already had someone whose job this is. Everyone else is finding out, again, that "we'll catch up on patches when we can" is not a real security posture.


5. The deeper lesson for Laravel and PHP teams


If you run Laravel on Apache, the patch is your problem. If you run Laravel behind NGINX, the patch is still your problem if any of the following are true: your staging server runs Apache, your CI runner exposes Apache for previews, an internal admin tool lives behind an Apache reverse proxy, or a legacy WordPress site shares the same edge. Treat the inventory step as the actual work. The patch is 30 seconds; the inventory is the hour. Most incident-response post-mortems in 2026 will trace back to an Apache (or NGINX, or IIS) instance that nobody on the current team remembered existed.


My Take


CVE-2026-23918 is the cleanest demonstration this year of why the modern attack surface is not "your codebase," it is "your inventory." The bug itself is a five-line cleanup-path mistake in h2_mplx.c. The reason it matters is that most operators do not have a current map of what is running where. The cost-effective defence is not better fuzzing of mod_http2; it is the boring discipline of keeping a current asset inventory, an owner per asset, and a 24-hour SLA on critical patches. Every time one of these CVEs lands, the same set of companies takes a clean hit and the same set takes a long one. It is not a question of luck. It is a question of whether the inventory existed before the disclosure landed. Build the inventory on a calm Wednesday, not under fire on a Thursday.


Sources



Cybersecurity Back to Blog