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_destroyapr_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_http2 loaded (default in most distribution packages, default in the official image).
  • Multi-threaded MPM (event is the modern default; worker also 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_STREAM with a non-zero error code in the same TCP segment or within microseconds of the initial HEADERS frame, 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_status scoreboard transitions, watch systemd Main PID changed events, and alert on SIGSEGV or SIGABRT in the apache user’s audit/coredump stream.
  • Surges of HTTP/2 GOAWAY frames from the server side, or sudden jumps in connection reset counters 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:

  1. Upgrade to httpd 2.4.67. This is the only complete fix.
  2. Where upgrade is blocked, switch the MPM to prefork. It costs throughput and concurrency but removes exposure to this specific bug.
  3. If neither is feasible, disable mod_http2 and serve HTTP/1.1 only. Browsers will negotiate down cleanly. Long-lived gRPC clients will not, so confirm dependencies.
  4. Rebuild and redeploy any container images derived from httpd:2.4.66. Pin to httpd:2.4.67 (or a digest), do not rely on a floating tag.
  5. 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.