Skip to main content
Vulnerability Database/CVE-2026-69213

CVE-2026-69213: Http4s Ember HTTP/2 DoS Vulnerability

CVE-2026-69213 is a denial of service vulnerability in Http4s Ember HTTP/2 that allows attackers to exhaust server memory through unbounded frame queues. This post covers technical details, affected versions, and mitigation.

Published:

CVE-2026-69213 Overview

Http4s is a Scala interface for HTTP services. CVE-2026-69213 is a resource exhaustion vulnerability [CWE-400] in the Ember HTTP/2 implementation. Prior to versions 0.23.35 and 1.0.0-M47, Ember serializes outbound frames through a single unbounded queue consumed by writeLoop. An unauthenticated remote attacker can send PING, SETTINGS, or DATA frames while refusing to read responses, forcing the server to enqueue acknowledgments and WINDOW_UPDATE frames faster than they drain. The behavior exhausts JVM heap memory on any server built with withHttp2, and it also affects ember-client when connected to a hostile HTTP/2 server.

Critical Impact

An unauthenticated network attacker can exhaust heap memory on Ember HTTP/2 servers and clients, causing denial of service.

Affected Products

  • Http4s Ember Server with HTTP/2 enabled (withHttp2) prior to 0.23.35
  • Http4s Ember Client with HTTP/2 enabled prior to 0.23.35
  • Http4s 1.0.0-M1 through 1.0.0-M46 milestone releases

Discovery Timeline

  • 2026-09-15 - CVE-2026-69213 published to NVD
  • 2026-09-17 - Last updated in NVD database

Technical Details for CVE-2026-69213

Vulnerability Analysis

The Ember HTTP/2 transport layer maintains one outbound frame queue per connection, consumed by an asynchronous writeLoop fiber. The queue is declared with cats.effect.std.Queue.unbounded, so producers never block regardless of consumer progress. When a peer stops reading from the underlying TCP socket, the writer fiber stalls while inbound control frames continue to arrive. Each inbound PING triggers a PING ACK enqueue, each SETTINGS triggers a SETTINGS ACK, and each DATA frame triggers a WINDOW_UPDATE. The producer side grows without bound while the consumer side is TCP-blocked.

Root Cause

The root cause is the absence of backpressure between HTTP/2 frame producers and the socket writer. The unbounded queue decouples frame generation from network flush progress. A // TODO revisit comment in both H2Client.scala and H2Server.scala marks the queue as unbounded, and no upstream flow control mechanism compensates for a slow or malicious peer.

Attack Vector

An unauthenticated attacker establishes an HTTP/2 connection to a vulnerable Ember server, then stops reading from the socket while flooding control frames. Because HTTP/2 mandates acknowledgment of PING and SETTINGS, the server is forced to enqueue responses. Symmetric exploitation applies to ember-client: a hostile HTTP/2 server can trigger the same heap exhaustion on connecting clients.

The upstream patch replaces the unbounded queue with a bounded, backpressured variant:

scala
// Before (vulnerable):
queue <- cats.effect.std.Queue.unbounded[F, Chunk[H2Frame]] // TODO revisit

// After (patched):
queue <- cats.effect.std.Queue.bounded[F, Chunk[H2Frame]](128)

Source: http4s commit 13fe24d

Detection Methods for CVE-2026-69213

Indicators of Compromise

  • Sustained JVM heap growth on Ember HTTP/2 processes without corresponding request throughput
  • OutOfMemoryError events in Ember server logs referencing H2Server or H2Client classes
  • High volumes of inbound HTTP/2 PING or SETTINGS frames from a single client with minimal read activity on the reverse channel
  • TCP send buffers persistently full on HTTP/2 sockets while connection state remains ESTABLISHED

Detection Strategies

  • Instrument Ember with JVM heap and GC metrics, and alert on rapid old-generation growth tied to HTTP/2 connections
  • Correlate HTTP/2 frame counters (via a reverse proxy or eBPF probe) against socket write throughput to identify producer/consumer imbalance
  • Inventory Scala services for http4s-ember-server and http4s-ember-client dependencies below 0.23.35 or milestone 1.0.0-M46 and earlier

Monitoring Recommendations

  • Track per-connection HTTP/2 frame type ratios at ingress and flag clients with skewed control-to-data ratios
  • Monitor process memory, thread state, and file descriptor counts for Ember-based JVMs
  • Ingest application logs and JVM telemetry into a centralized data lake to correlate DoS symptoms across replicas

How to Mitigate CVE-2026-69213

Immediate Actions Required

  • Upgrade http4s-ember-server and http4s-ember-client to 0.23.35 for the stable line or 1.0.0-M47 for the milestone line
  • Audit dependency graphs for transitive Ember usage and rebuild affected artifacts
  • Restart long-running Ember services after upgrade to release any accumulated heap pressure

Patch Information

The fix landed in the v0.23.35 release and the v1.0.0-M47 release. The patch replaces the unbounded outbound queue in H2Client.scala and H2Server.scala with a bounded queue of capacity 128, applying backpressure to frame producers when the socket writer falls behind. Full details are in GHSA-8f3q-3jmv-7prw.

Workarounds

  • Disable HTTP/2 by removing withHttp2 from Ember server and client builders until upgrade is possible
  • Terminate HTTP/2 at a hardened reverse proxy such as Envoy or Nginx and downgrade to HTTP/1.1 for the Ember backend
  • Apply per-connection rate limits on HTTP/2 PING and SETTINGS frames at the edge
  • Constrain JVM heap sizing and enable OOM restart policies to bound blast radius
bash
# sbt dependency upgrade
libraryDependencies ++= Seq(
  "org.http4s" %% "http4s-ember-server" % "0.23.35",
  "org.http4s" %% "http4s-ember-client" % "0.23.35"
)

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.