Apache HTTP/2 CVE-2026-23918: the double-free that threatens your web servers and Docker containers

Technical analysis of CVE-2026-23918 (CVSS 8.8): a double-free in Apache 2.4.66's mod_http2 enabling unauthenticated DoS and RCE. Root cause in h2_mplx.c, exploitation conditions, heightened risk on Debian/Docker, and remediation.

On May 4, 2026, the Apache Software Foundation released version 2.4.67 of its HTTP server, fixing five vulnerabilities. The most severe, CVE-2026-23918 (CVSS 8.8), is a double-free in the HTTP/2 implementation that allows a trivial denial of service and, in certain configurations, unauthenticated remote code execution. And the worst part: it affects the default configurations of many Debian distributions and official Docker images.

Since Apache httpd is one of the most widely deployed web servers in the world, and HTTP/2 is enabled by default, this flaw is worth a closer look — not just to patch it, but to understand why a memory-management bug that's several years old only became exploitable now.

What are we talking about? The double-free in a nutshell

A double-free (CWE-415) occurs when a program frees the same region of memory twice. The second call to free() operates on a pointer that no longer belongs to it: depending on the allocator's state, this triggers a crash (DoS) or, if an attacker controls what was reallocated in the meantime, a heap corruption that can be exploited to hijack the execution flow (RCE).

Here, the doubly freed region is an HTTP/2 stream object (h2_stream), destroyed twice during stream cleanup in mod_http2.

The root cause: a duplicated stream cleanup

The vulnerability lives in the stream cleanup path, specifically in h2_mplx.c. The trigger is a timing issue in the ordering of HTTP/2 frames:

The client sends a HEADERS frame immediately followed by a RST_STREAM with a non-zero error code, on the same stream, before the multiplexer has registered that stream.

Two callbacks from the nghttp2 library then fire in sequence:

  • on_frame_recv_cb (for the RST_STREAM)
  • on_stream_close_cb (for the stream close)

Both end up calling h2_mplx_c1_client_rst → m_stream_cleanup, which pushes the same h2_stream pointer twice onto the spurge cleanup array. Later, c1_purge_streams walks this array and calls h2_stream_destroy → apr_pool_destroy on each entry. The second pass hits memory that is already freed: double-free.

The core of the problem is unsynchronized ownership tracking between the HTTP/2 cleanup callbacks — exactly the kind of concurrency bug that multithreaded servers make hard to reason about.

Why only now? The effect of an allocator change

The most instructive detail: the latent bug probably existed earlier, but it only became an exploitable double-free with version 2.4.66, due to a memory allocator change in mod_http2 v2.0.33 shipped with that release. It's a classic reminder: a security vulnerability isn't just a faulty line of code, it's also the execution context that makes it (or not) triggerable.

Key takeaway for triage: most analyses converge on 2.4.66 specifically as the practically exploitable version. If you're on 2.4.65 or earlier, the double-free risk is significantly lower — but updating is still recommended (the 4 other CVEs fixed in 2.4.67).

Are you vulnerable? The three conditions

Three prerequisites must be met:

  1. Apache HTTP Server 2.4.66 (the version where the allocator makes the bug exploitable).
  2. HTTP/2 enabled — which is the default as soon as mod_http2 is loaded in 2.4.66.
  3. A multithreaded MPM: worker or event. The prefork MPM (single-threaded) is not affected, since the bug doesn't manifest in that model.

Quick check:

# Apache version (watch out for distro backports)
httpd -v        # RHEL/CentOS
apache2ctl -v   # Debian/Ubuntu

# Is mod_http2 loaded?
apache2ctl -M 2>/dev/null | grep http2

# Current MPM
apache2ctl -V 2>/dev/null | grep -i mpm

Trivial DoS, conditional RCE: the real risk level

The two impacts must be distinguished:

  • Denial of service — the path is trivial and requires no authentication: a few well-ordered frames are enough to crash the worker processes. One source reports DoS exploitation already observed in the wild.
  • Remote code execution — far more sophisticated, but proven viable by the researchers. It is made easier on deployments using APR with mmap — precisely the configuration of Debian systems and official Docker images. A PoC exists; no mass public RCE exploitation observed to date.

In other words: if you're running Apache 2.4.66 in an official Docker container, you're in the most exposed scenario. The flaw was discovered by Bartlomiej Dmitruk and Stanislaw Strzalkowski during an internal code review, and reported on December 10, 2025.

Remediation: patch, or mitigate in the meantime

The only complete remediation is upgrading to Apache 2.4.67+, which removes the vulnerable cleanup path entirely.

If you can't patch immediately, two effective mitigations:

  1. Disable mod_http2: the vulnerable code is then no longer executed.
    # Debian/Ubuntu
    sudo a2dismod http2 && sudo systemctl restart apache2
  2. Switch to the prefork MPM: the bug doesn't manifest in this single-threaded model (at the cost of lower performance).

Distributions have backported the fix — for example the USN-8239-1 advisory for Ubuntu. Check your package manager rather than relying on the upstream version number alone.

Warning: disabling HTTP/2 only fixes CVE-2026-23918. The four other flaws patched in 2.4.67 remain open. A full update must stay the priority.

Detection: spotting an exploitation attempt

Watch for the following signals:

  • Repeated crashes of Apache worker processes (the main DoS symptom).
  • Log entries mentioning double-free or heap corruption.
  • Abnormal HTTP/2 traffic: bursts of HEADERS immediately followed by RST_STREAM.
  • Core dumps related to memory management — to be analyzed.

For fine-grained kernel-level runtime detection (abnormal child processes, crashes), an eBPF-based tool like Falco is ideal.

The lesson: HTTP/2, a recurring attack surface

CVE-2026-23918 isn't an isolated case. The HTTP/2 implementation — with its multiplexing, concurrent streams, and complex state management — has become a recurring source of vulnerabilities across all servers (remember the "Rapid Reset" family and its relatives). Concurrency and manual memory management in C make for a cocktail ripe for use-after-free and double-free bugs.

Two reflexes to ingrain: treat every exposed server as a critical asset to patch as a priority, and reduce the surface — only enable HTTP/2 if you actually use it, segment, and place a defensive layer upstream. That's the logic of a Zero Trust architecture applied all the way down to the web layer. And if you're still torn between Apache and its competitor, our NGINX configuration guide details a robust alternative.

Did you enjoy this article?

Comments

Morgann Riu

Cybersecurity and Linux administration expert. I help companies secure and optimize their critical infrastructures.

Back to the blog

Checklist Sécurité Linux

30 points essentiels pour sécuriser un serveur Linux. Recevez aussi les nouveaux tutoriels par email.

Pas de spam. Désabonnement en 1 clic.