Apache HTTP/2 Double-Free in mod_http2 (CVE-2026-23918): Defender’s Read
On May 5, 2026 the Apache Software Foundation shipped httpd 2.4.67 to fix CVE-2026-23918, a double-free in mod_http2 that earned a CVSS of 8.8 and applies to the prior release, 2.4.66. The denial-of-service path is one TCP connection and two HTTP/2 frames — no auth, no specific URL, no exotic header. The remote-code-execution path is narrower in preconditions but plausible enough that ISSOs should treat any internet-reachable httpd 2.4.66 with HTTP/2 enabled as a same-week patch. The fact that the affected release is the current line, that mod_http2 ships in default builds, and that the official httpd Docker image uses the APR mmap allocator that makes the RCE chain practical means this is not a theoretical worry for hardened lab installs only.
Details below are drawn from the disclosure thread on the httpd security list (https://lists.apache.org/thread/otwt07gfnp6x2b58hnbghgs9r4ovy3yf), the CVE record (https://www.cve.org/CVERecord?id=CVE-2026-23918), and the researchers’ write-up summarized by The Hacker News (https://thehackernews.com/2026/05/critical-apache-http2-flaw-cve-2026.html). Bartlomiej Dmitruk (Striga.ai) and Stanislaw Strzalkowski (ISEC.pl) are credited.
What the bug actually is
The defect lives in h2_mplx.c, in the stream cleanup path of the HTTP/2 multiplexer. When a client sends a HEADERS frame immediately followed by a RST_STREAM carrying a non-zero error code on the same stream — and does so before the multiplexer has registered that stream — two nghttp2 callbacks fire in sequence. Both on_frame_recv_cb (for the RST) and on_stream_close_cb (for the close) end up calling h2_mplx_c1_client_rst, which calls m_stream_cleanup, which pushes the same h2_stream pointer onto the spurge cleanup array twice. When c1_purge_streams later iterates spurge and invokes h2_stream_destroy → apr_pool_destroy on each entry, the second call frees memory that has already been freed.
Classic double-free, classic exploitation surface. On a multi-threaded MPM (event or worker) the worker process crashes and httpd respawns it, but every in-flight request on that worker dies with it. mpm_prefork is not affected because its process model never reaches the racy multiplexer path the same way. The RCE chain depends on the Apache Portable Runtime being built with the mmap allocator, which is the default on Debian-derived distributions and on the upstream httpd Docker image. Other allocator builds limit attackers to repeatable DoS — which, for an internet-facing reverse proxy, is already an availability incident worth declaring.
Who is exposed
If you can answer yes to all three of these, you are in scope:
- httpd 2.4.66 in production or in any path serving traffic.
mod_http2loaded (default in most distribution packages, default in the official image).- Multi-threaded MPM (
eventis the modern default;workeralso qualifies).
The quickest inventory pass is httpd -v and httpd -M | grep -E 'http2|mpm' on each host, plus a check of any container images pinned to httpd:2.4.66, httpd:2.4, or unspecified latest tags pulled within the affected window. Don’t forget appliances, load balancers, and vendor stacks that embed httpd — VMware, Atlassian, IBM HTTP Server derivatives, and a long tail of OEM management interfaces have historically lagged upstream by weeks to months.
Detection
There is no CVE-specific signature you should trust as a sole control, but the trigger pattern is distinctive enough to write narrow detections against:
- HTTP/2 streams that receive a client
RST_STREAMwith a non-zero error code in the same TCP segment or within microseconds of the initialHEADERSframe, repeated across many streams from the same source. Most legitimate clients do not cancel a stream they just opened in the same flight. - Worker process crashes and respawns on httpd hosts. Tail
mod_statusscoreboard transitions, watchsystemdMain PID changedevents, and alert onSIGSEGVorSIGABRTin the apache user’s audit/coredump stream. - Surges of HTTP/2
GOAWAYframes from the server side, or sudden jumps inconnection resetcounters at the L4 load balancer fronting httpd.
If you run a WAF or HTTP/2-aware reverse proxy in front (Envoy, HAProxy, NGINX, a CDN), terminate HTTP/2 there and forward HTTP/1.1 to the vulnerable httpd until patched. That collapses the attack surface to the front tier, which is presumably not running Apache 2.4.66.
Remediation
In priority order:
- Upgrade to httpd 2.4.67. This is the only complete fix.
- Where upgrade is blocked, switch the MPM to
prefork. It costs throughput and concurrency but removes exposure to this specific bug. - If neither is feasible, disable
mod_http2and serve HTTP/1.1 only. Browsers will negotiate down cleanly. Long-lived gRPC clients will not, so confirm dependencies. - Rebuild and redeploy any container images derived from
httpd:2.4.66. Pin tohttpd:2.4.67(or a digest), do not rely on a floating tag. - For appliances, open vendor tickets now and capture the response in your POA&M. Do not assume a vendor rebuild is imminent.
Verify post-patch with httpd -v and a config sanity test; for containers, confirm the running image digest, not just the tag.
NIST 800-53 mapping
| Control | Application |
|---|---|
| SI-2 Flaw Remediation | Patch tracking, deployment SLA, exception handling for any 2.4.66 left in service |
| SI-3 / SI-4 | Detections for the trigger pattern and worker-crash telemetry |
| SI-7 Software, Firmware, and Information Integrity | Image digest pinning, rebuild verification |
| SC-5 Denial of Service Protection | Front-tier HTTP/2 termination, rate limiting on RST_STREAM storms |
| SC-7 Boundary Protection | Limiting which httpd instances are reachable from untrusted networks while patching rolls |
| CM-2 / CM-6 / CM-8 | Inventory of httpd versions, MPM, and loaded modules across hosts and images |
| RA-5 Vulnerability Monitoring and Scanning | Authenticated scans that catch httpd 2.4.66, not just banner grabs that may lie behind a proxy |
| SR-3 / SR-4 Supply Chain | Vendor appliances embedding httpd; SBOM queries against apache-httpd 2.4.66 |
| IR-4 Incident Handling | Treat sustained worker-crash patterns as availability incidents, not noise |
The takeaway
This is the kind of bug that hits the boring middle of an environment — the reverse proxies, the legacy app fronts, the management consoles nobody re-reviews after the initial ATO. The DoS works against a default install. The RCE works against a default Debian package and the upstream Docker image. The fix is one minor version, the workarounds are well understood, and the detections are cheap. Patch the 2.4.66 hosts this week, audit the container images by digest, and write the RST_STREAM-storm rule before someone else writes a scanner that fires it at you.