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

CVE-2026-69210: Http4s WebSocket DoS Vulnerability

CVE-2026-69210 is a denial of service flaw in Http4s WebSocket FrameTranscoder that allows remote attackers to cause infinite loops and resource exhaustion. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-69210 Overview

CVE-2026-69210 is a denial-of-service vulnerability in http4s, a Scala interface for HTTP services. The flaw resides in the WebSocket FrameTranscoder.bodyLength function, which rejects extended payload lengths above Integer.MAX_VALUE but permits negative 64-bit lengths. A remote client that completes a WebSocket handshake through an Ember server can send a crafted frame that causes the decoder to return an empty frame without advancing its input. The decode loop then runs indefinitely, pinning a worker at full CPU and growing an ArrayBuffer without bound. The issue is fixed in versions 0.23.35 and 1.0.0-M47.

Critical Impact

Unauthenticated remote attackers can trigger an infinite decode loop that exhausts CPU and memory on any http4s Ember server accepting WebSocket connections.

Affected Products

  • http4s versions prior to 0.23.35
  • http4s 1.0.0 milestone releases prior to 1.0.0-M47
  • Applications using the http4s Ember server with WebSocket support

Discovery Timeline

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

Technical Details for CVE-2026-69210

Vulnerability Analysis

The vulnerability is classified as CWE-835 (Loop with Unreachable Exit Condition, or infinite loop). The defect lives in core/shared/src/main/scala/org/http4s/websocket/FrameTranscoder.scala, which parses WebSocket frame headers per RFC 6455 §5.2. When the length indicator equals 127, the transcoder reads the next 8 bytes as a Long and compares it against Integer.MAX_VALUE using signed arithmetic. Negative Long values pass the check because signed comparison treats them as smaller than Integer.MAX_VALUE.

With a negative length accepted, downstream logic returns an empty frame without consuming input bytes from the buffer. The Ember server's decode loop invokes the transcoder repeatedly on the same unadvanced buffer, never terminating. Each iteration appends to an ArrayBuffer, driving unbounded memory growth in addition to sustained CPU consumption on the worker thread.

Root Cause

The root cause is a signed versus unsigned comparison error. RFC 6455 defines the extended payload length as a 64-bit unsigned integer, but http4s reads it into a signed Long and then compares against a signed 32-bit Int bound. The original guard if (l > Integer.MAX_VALUE) fails to reject negative values, which arise when the high bit of the unsigned 64-bit length is set.

Attack Vector

Exploitation requires network access to an http4s Ember endpoint that upgrades HTTP connections to WebSocket. No authentication or user interaction is needed. The attacker completes the standard WebSocket handshake, then sends a single frame whose 8-byte extended length field encodes a value with the sign bit set. The server worker enters the infinite decode loop immediately.

scala
     else if (len == 126) (in.get(2) << 8 & 0xff00) | (in.get(3) & 0xff)
     else if (len == 127) {
       val l = in.getLong(2)
-      if (l > Integer.MAX_VALUE) throw new FrameTranscoder.TranscodeError("Frame is too long")
+      // RFC6455 §5.2: the payload length should be interpreted as a 64-bit
+      // unsigned int, but we read it into a 64-bit signed Long and then
+      // truncate into a 32-bit signed Int.  That's fine for reasonable
+      // values, but can result in a negative
+      if (java.lang.Long.compareUnsigned(l, Int.MaxValue) > 0)
+        throw new FrameTranscoder.TranscodeError("Frame is too long")
       else l.toInt
     } else throw new FrameTranscoder.TranscodeError("Length error")
   }

Source: http4s patch commit c7d3ef9. The fix replaces the signed comparison with java.lang.Long.compareUnsigned, correctly rejecting frames whose unsigned length exceeds Int.MaxValue.

Detection Methods for CVE-2026-69210

Indicators of Compromise

  • Sustained 100% CPU utilization on one or more JVM worker threads handling WebSocket traffic
  • Rapid heap growth or OutOfMemoryError events in http4s Ember server logs shortly after a WebSocket upgrade
  • WebSocket connections from a single client that remain open with no legitimate frame traffic returned

Detection Strategies

  • Inventory Scala and JVM services for http4s versions below 0.23.35 or 1.0.0-M47 using software composition analysis tooling
  • Inspect WebSocket frames at ingress for extended payload length fields (opcode length byte 127) where the 8-byte length has the high bit set
  • Correlate WebSocket handshake events with subsequent thread saturation on the same worker to identify exploitation attempts

Monitoring Recommendations

  • Alert on JVM thread CPU time exceeding sustained thresholds for blaze or ember worker pools
  • Track ArrayBuffer allocation rates and heap pressure per WebSocket session using JVM Flight Recorder or Micrometer
  • Log and rate-limit WebSocket upgrade requests at the reverse proxy to bound blast radius

How to Mitigate CVE-2026-69210

Immediate Actions Required

  • Upgrade http4s to 0.23.35 (stable) or 1.0.0-M47 (milestone) across all services exposing WebSocket endpoints
  • Restart affected JVM processes after dependency upgrade to ensure the patched FrameTranscoder is loaded
  • Audit application dependency trees for transitive http4s pulls that may lag the direct dependency version

Patch Information

The fix is available in http4s v0.23.35 and http4s v1.0.0-M47. Technical details are documented in GitHub Security Advisory GHSA-3j86-pj9g-jchr.

Workarounds

  • Disable WebSocket routes in http4s applications until the upgrade can be deployed
  • Terminate WebSocket traffic at an upstream proxy that validates frame length fields and rejects unsigned lengths above Integer.MAX_VALUE
  • Enforce per-connection CPU and memory quotas on JVM workers to contain resource exhaustion from a single client
bash
# Update the http4s dependency in build.sbt
libraryDependencies ++= Seq(
  "org.http4s" %% "http4s-ember-server" % "0.23.35",
  "org.http4s" %% "http4s-dsl"          % "0.23.35"
)

# Refresh and rebuild
sbt clean update compile

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.