CVE-2026-23918 — the mod_http2 double-free in Apache 2.4.66, in operator terms
On 5 May 2026 the Apache HTTPD team disclosed the flaw now tracked as CVE-2026-23918: a double-free in mod_http2, more precisely in the stream cleanup path of h2_mplx.c. Fixed in Apache HTTP Server 2.4.67. CVSS 8.8. One TCP connection, two HTTP/2 frames, and the worker crashes — on every default deployment with mod_http2 and a multi-threaded MPM. On Debian-derived distributions, where the Apache Portable Runtime ships the mmap allocator as the default, the flaw is not a pure DoS but remotely exploitable to Remote Code Execution. Two public PoCs on GitHub deliver both the DoS and the detection vector.
What happened? If you were still running HTTP/2 on Apache 2.4.66 on Debian, Ubuntu or any derived image on the evening of 5 May, you have been running a pre-auth RCE path for eight days. No CISA KEV entry, no documented active exploitation, but public PoCs and a trivial trigger sequence.
Why does it matter? TYPO3 and Sylius hosting in the German Mittelstand still runs predominantly on Apache 2.4 with mod_http2 and a Debian/Ubuntu base in 2026. If you operate the HTTP front-end stack yourself, you have a concrete 48-hour patch obligation today.
Who should keep reading? Platform operators of TYPO3 or Sylius hosting, operators of mixed PHP webserver fleets, and teams that pin Apache 2.4.66 in container images, Docker Compose stacks or Helm charts.

TL;DR — 90 seconds
A trivial crash pattern, a documented RCE path on Debian default, and eight days since disclosure with a public PoC.
- Affected?
Apache HTTP Server 2.4.66 with
mod_http2enabled and a multi-threaded MPM (event,worker). In practice all TYPO3 and Sylius hosting in the German Mittelstand that enabled HTTP/2 for performance. Earlier 2.4 lines are, per Apache, not affected.- Risk?
DoS trivial — one TCP connection, two HTTP/2 frames. RCE remote on Debian/Ubuntu default with APR
mmapallocator. CVSS 8.8.- Immediate action?
Upgrade to Apache 2.4.67. If the maintenance window will not open within the next 24 hours: set
Protocols http/1.1, disablemod_http2temporarily.- Recommendation?
Mittelstand: distribution patch in the current maintenance window, HTTP/1.1 stopgap fallback until then. Enterprise: curated image promotion onto patched base images, WAF rule on the HEADERS → RST_STREAM with non-zero error code frame sequence.
- Criticality?
See hero badge —
high.
What is the problem?
The flaw sits in the stream cleanup path of mod_http2, technically in h2_mplx.c. The trigger sequence is sober: a client sends an HTTP/2 HEADERS frame, immediately followed by an RST_STREAM frame with a non-zero error code, on the same stream, before the multiplexer has even registered the stream. Two nghttp2 callbacks fire in sequence: on_frame_recv_cb for the RST and on_stream_close_cb for the close. Both then call h2_mplx_c1_client_rst → m_stream_cleanup, which pushes the same h2_stream pointer onto the spurge cleanup array twice. When c1_purge_streams later iterates spurge and calls h2_stream_destroy, the second call hits already-freed memory. That is the classical double-free condition.
The DoS path is therefore trivial. A single attacking client can crash a worker with one TCP connection and two frames. Apache restarts the worker by default, but if the attacker runs this in a loop, effective availability of the HTTPS frontline drops to zero.
The RCE path is the structurally heavy part. The Apache Portable Runtime knows two allocators for its pool mechanism: a private heap allocator and an mmap-based allocator. On Debian, Ubuntu and all derived distributions the mmap allocator is the default. An attacker can occupy the freed virtual address via mmap reuse with a crafted, fake h2_stream struct whose pool cleanup function points to system(), and use Apache scoreboard memory as a stable container to make exploitation deterministic.
Who is affected?
A compact overview of affected and unaffected configurations:
| Stack | Affected | Not affected / conditions |
|---|---|---|
| Apache HTTP Server 2.4.66 | Default build with mod_http2 enabled and multi-threaded MPM | 2.4.67 and higher; mod_http2 disabled; pure prefork MPM without the HTTP/2 module |
| Debian 12 / 13 | Apache 2.4.66 from the distribution repository, APR with mmap allocator (default) — RCE path open | Apache 2.4.67 backport applied or HTTP/2 disabled |
| Ubuntu 24.04 / 26.04 LTS | Apache 2.4.66 from the distribution repository, APR mmap default — RCE path open | 2.4.67 update applied via unattended-upgrades |
| RHEL / Rocky / AlmaLinux 9 | Apache 2.4.66 from AppStream; APR typically private heap allocator, DoS path only | 2.4.67 update applied via dnf upgrade |
Docker httpd:2.4, httpd:2.4.66 | All image tags before the 2.4.67 bump | Freshly pulled httpd:2.4 tags after the bump |
| Wolfi-based Apache containers | All before the apk index update of the current week | Rebuilt image after apk upgrade |
| nginx, Caddy, HAProxy, Traefik | Not affected by the Apache cluster — separate HTTP/2 implementations | — |
| TYPO3 / Sylius behind a reverse proxy | Apache as a reverse proxy speaking HTTP/2 outward is directly affected | Apache as pure origin behind an nginx proxy with HTTP/1.1 downstream is not affected |
If you exposed Apache 2.4.66 with mod_http2 on a Debian/Ubuntu base on the public internet in the last eight days, you ran a pre-auth RCE path for eight days. We treat the inventory operationally as “exploitable until proven otherwise” — not as “compromised”, but no longer at the trust state of 4 May either.
Impact
CVSS 8.8 (High); Apache classifies the advisory as Critical due to the combination of a trivial DoS path and a documented RCE path on Debian default. In the German Mittelstand the affected configuration is the standard form: Apache 2.4 is the default web server in Plesk, cPanel, ISPConfig, and the standard container image for PHP workloads. HTTP/2 has been enabled on most Mittelstand client hosts since around 2018.
A compromised webserver frontline on a TYPO3 or Sylius client host means operational access to local cleartext source code, the running PHP-FPM pools with all active backend user sessions, the database connection via credentials stored in configuration, the cloud provider token from systemd unit or container init, and the backup path with all historical content. On Sylius hosting, direct access to the Stripe / Mollie / Adyen API credential is added if it lives as an environment variable.
Mitigation and immediate actions
Three paths, depending on maintenance window and distribution discipline.
Path 1 — distribution patch (recommended)
# Debian / Ubuntu
sudo apt-get update
sudo apt-get install --only-upgrade apache2
# RHEL / Rocky / AlmaLinux
sudo dnf upgrade httpd
# Check version
apache2 -v # or httpd -v
# Expected: Apache/2.4.67 or higher
Path 2 — pull container image fresh
# Standard Docker image
docker pull httpd:2.4
docker pull httpd:2.4-alpine
# In Compose setups
docker compose pull
docker compose up -d --force-recreate webserver
# In Helm charts
helm upgrade <release> <chart> \
--set image.tag=2.4.67 \
--reuse-values
Path 3 — stopgap, if no maintenance window in the next 24 hours
# /etc/apache2/conf-available/disable-http2.conf
# Apache falls back to HTTP/1.1, mod_http2 is not addressed
Protocols http/1.1
# Linux: enable configuration and reload Apache
sudo a2enconf disable-http2
sudo systemctl reload apache2
# RHEL line
echo "Protocols http/1.1" | sudo tee /etc/httpd/conf.d/disable-http2.conf
sudo systemctl reload httpd
Verify HTTP/2 is actually off:
curl --http2 -I tenant.example.com 2>&1 | head -5
# Expected: HTTP/1.1 200 OK (not HTTP/2 200)
ModSecurity will not detect the trigger sequence at the TCP layer directly. A WAF rule is primarily useful for catching repeated trigger attempts, not as sole mitigation. The patch remains the only complete fix.
Detection and validation
Three complementary detection paths we run in parallel.
Path 1: Access log pattern for unrealistic HEADERS / RST sequences
Check the last 7–10 days. Apache does not log RST_STREAM frames in detail through the normal mod_http2 logging path; the indicator is indirect — short connection lifetime with immediate stream reset and HTTP status 400/499.
# Check Apache error log for mod_http2 crash hints
sudo grep -E "h2_(stream|mplx)|child pid .* exit signal|Segmentation fault" \
/var/log/apache2/error.log* | tail -50
Path 2: Falco rule for Apache worker crashes with an unusual process tree
# /etc/falco/rules.d/apache-h2-crash.yaml
- rule: Apache worker unexpected exit with mod_http2
desc: Apache worker died abnormally while serving mod_http2 — possible CVE-2026-23918 exploitation
condition: >
proc_exit and
proc.name in (apache2, httpd) and
proc.exitcode != 0 and
proc.aname[1] in (apache2, httpd)
output: >
Apache worker exited abnormally: pid=%proc.pid exitcode=%proc.exitcode cmdline=%proc.cmdline
priority: WARNING
tags: [apache, mod_http2, cve-2026-23918]
Path 3: Tetragon TracingPolicy as an eBPF alternative
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: apache-mod-http2-anomaly
spec:
kprobes:
- call: "sys_munmap"
syscall: true
args:
- index: 0
type: "uint64"
- index: 1
type: "size_t"
selectors:
- matchBinaries:
- operator: "In"
values:
- "/usr/sbin/apache2"
- "/usr/sbin/httpd"
matchActions:
- action: "Audit"
PoC validation in your own client inventory
If you have a staging environment with Apache 2.4.66, you can use one of the public PoCs to validate the detection rule in passive mode — the xeloxa PoC supports a --detection-only mode that does not run the crash trigger but only sends the fingerprint sequence. Do not run it against production hosts.
Operator recommendation
The operational question is not “patch or not?”, but “when does the next maintenance window open?” and “who carries the risk for the eight days between disclosure and your own patch?”.
Operational decision block — patch window now vs. stopgap fallback
- Patch immediately if the host carries a TYPO3 or Sylius client frontline, is publicly reachable on 443, and runs Apache 2.4.66 with
mod_http2from the Debian/Ubuntu repo. - Use the HTTP/1.1 stopgap fallback if the maintenance window does not open within 24 hours but the host is publicly reachable. The performance impact from forgoing HTTP/2 is measurable but tolerable.
- Standard maintenance cycle is fine if the host sits behind an HTTP/1.1 downstream reverse proxy and the
mod_http2path is not reachable. - Awareness only if no Apache 2.4.66 instance is reachable in the client inventory (nginx-only stack).
Mittelstand
Distribution patch in the current maintenance window. If you have unattended-upgrades configured on Debian/Ubuntu, review the next 24 hours of runs — the 2.4.67 bump typically arrives via the apt-security line, requires no reboot, but does require an Apache reload. The HTTP/1.1 stopgap fallback is the second line of defence.
Enterprise
Curated image promotion onto patched Apache 2.4.67 base images. WAF rule on the HEADERS / RST frame sequence as an additional layer that stays useful after the patch. Add client frontline hosts to the 24-hour early-patch pool, not the 14-day standard cycle.
Kubernetes platform
Rebuild container images that contain Apache 2.4.66. Pin Helm chart values to the patched tag, run cluster-wide rollout in the standard maintenance window, with priority for client frontline hosts. Roll out the Falco rule from the detection section cluster-wide.
- Sub-scenario Kubernetes Ingress with Apache sidecar: Update sidecar image tag in the pod template spec, rolling update via
kubectl rollout restart. - Sub-scenario Helm-based TYPO3 charts: Check
image.repositoryandimage.taginvalues.yaml— often pinned to older Apache tags.
Declarative stacks (NixOS / Talos / Flatcar / Wolfi)
Update NixOS modules for apacheHttpd as soon as the nixpkgs bump to 2.4.67 is merged (as of 13 May: already merged, available on most channels). Wolfi-based Apache containers close the gap via the apk index update of the current week — trigger an image rebuild on Wolfi base with apk upgrade.
What we actually did
On 13 May 2026, between 07:15 and 08:30 CEST, we ran three disciplines.
First the inventory: every client host under our operation was queried with apache2 -v or httpd -v, plus the container tags of all TYPO3 and Sylius client images with docker image ls | grep httpd. Three hosts were on 2.4.66 (all Debian 12 base, all with mod_http2 enabled), two container images on httpd:2.4.66. The remaining hosts run on nginx or are already on 2.4.67.
Then the patch: apt-get install --only-upgrade apache2 on the three affected hosts; container images repulled with docker pull httpd:2.4 && docker compose up -d --force-recreate webserver. On a Plesk-managed host the distribution patch had to be pulled via the Plesk web UI because the apt repo is overlaid by a Plesk mirror — added a note to the client onboarding guide.
Finally the detection stage: the Falco rule Apache worker unexpected exit with mod_http2 was activated on two cluster platforms. An access log pattern check over the last 10 days yielded no client log with notable clusters of short connection lifetimes with stream reset.
The structural lesson of this flaw lies in the interaction between nghttp2 callback ordering and the APR allocator choice. The error in 2.4.66 is not in nghttp2 but in mod_http2's assumption that the two callbacks will not both trigger the cleanup path for an unregistered stream. They do. The APR allocator choice is the second lever: on Debian-based distributions mmap has historically been compiled as the default. That mmap default is the lever that turns the double-free into a pre-auth RCE path. This is the direct continuation of the line we opened with CVE-2026-31431 “Copy Fail” as the “distribution is the architecture” finding.
Frequently asked questions about the Apache mod_http2 double-free (CVE-2026-23918)
Does TYPO3 hosting on Plesk or cPanel need to be patched immediately because of CVE-2026-23918?+
Yes, as soon as the Plesk or cPanel mirror picks up the 2.4.67 bump. Plesk runs its own patch wave that typically arrives 24–72 hours after the distribution patch. Until then the HTTP/1.1 stopgap fallback can be set via the Plesk Apache Tweaks section (Hosting → Apache & nginx Settings → Additional directives for HTTPS): Protocols http/1.1. Apache reload happens automatically via the Plesk apply routine.
How do I check whether my Sylius client host really runs Apache 2.4.66 with mod_http2?+
apache2 -v (Debian/Ubuntu) or httpd -v (RHEL) for the version. apache2ctl -M | grep http2 or httpd -M | grep http2 for the module. curl --http2 -I shop.tenant.example.com for a live check that HTTP/2 is actually active on the client frontline.
Are TYPO3 sites hosted behind Cloudflare automatically protected against CVE-2026-23918?+
Partially. Cloudflare terminates TLS and HTTP/2 itself and typically speaks HTTP/1.1 or HTTP/2 to the origin — the configuration sits in the Cloudflare dashboard under Network → HTTP/2 to Origin. If HTTP/2 to origin is disabled, the origin path is not directly reachable; if the origin path itself is publicly reachable on 443 (a common setup), the flaw remains open. We recommend patching independently of the Cloudflare status.
Do Wolfi-based Apache containers need to be rebuilt because of CVE-2026-23918?+
Yes. Wolfi-based apache2 containers close the gap via the apk index update of the current week — trigger an image rebuild on Wolfi base with apk upgrade, pin the Helm chart to the new image tag, roll out in the standard maintenance window.
Is the HTTP/1.1 stopgap fallback enough as sole mitigation for the next few days?+
Yes, with a caveat. Setting Protocols http/1.1 disables the mod_http2 code path entirely — the flaw is no longer reachable. The performance impact from forgoing HTTP/2 is measurable (latency rise for many small assets, since multiplexing falls away), but operationally tolerable in the 24–72-hour window until the real patch. Do not run this as a permanent mitigation.
Is the Apache finding structurally connected to the VS Code cluster from 12 May?+
Structurally no — the flaws sit on different layers (web server frontline vs. developer workstation). Operationally yes, because both push the client platform operator into the same 48-hour patch corridor. Rolling out both patches synchronously today eases the load on the next client maintenance window.
Conclusion
CVE-2026-23918 is not the most spectacular finding of the May patch cycle — no active exploitation in the wild, no CISA KEV entry, no BSI special report. What makes the finding operationally heavy is its triviality on the trigger side combined with the structural RCE path condition on Debian default. One TCP connection, two frames, one fewer client host. And the PoCs have been public for eight days.
The question is not whether 2.4.67 is enough — it is enough for the specific code path Apache closed on 5 May. The question is whether your platform runs the HTTP front-end layer as its own patch and detection responsibility, or whether you continue to treat the front-end frontline as a “comes with the distribution update” component. The structural answer is the first variant, with its own inventory, its own early-patch cohort, and its own WAF rule discipline.
Personal background and technical details on hardening Apache frontlines in the German Mittelstand: ole-hartwig.eu.
We assess, patch and validate productive Apache 2.4 frontlines against CVE-2026-23918.
Inventory of the TYPO3 and Sylius hosting estate, HTTP/1.1 stopgap fallback where needed, distribution patch to 2.4.67 in the maintenance window, WAF rule against the HEADERS / RST frame sequence, PoC-based detection validation on staging.
If you operate TYPO3 or Sylius hosting in the German Mittelstand, run Apache 2.4 as your client frontline in self-managed operations, or maintain a curated container image line on Apache base — let's talk before the next client maintenance window. Take a look at our standard line for DevSecOps platform operations and TYPO3 platform operations.

![[Translate to English:] Foto von Kai Ole Hartwig.](/fileadmin/_processed_/e/9/csm_ole-neu_73323ad80d.jpeg)

![[Translate to English:] Hölzerner Setzkasten mit präzisem Raster aus Edelstahl-Würfeln auf glattem Beton; in drei Fächern stehen leicht abweichende Messing-Würfel gleicher Größe als stille Substitution. Daneben eine Kraftpapier-Etikette mit oxblutfarbenem Faden und eine messingfarbene Juwelierlupe im kühlen Nordlicht.](/fileadmin/_processed_/5/b/csm_0d49848511671c27dc01822451c27320dd11fa770ba1b43b9369bbf3178f8480_3232cf94e2.jpg)
