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

CVE-2026-42786: Bandit WebSocket DoS Vulnerability

CVE-2026-42786 is a denial of service flaw in Bandit WebSocket that allows memory exhaustion through unbounded continuation frames. This article covers the technical details, affected versions, and mitigation.

Published:

CVE-2026-42786 Overview

CVE-2026-42786 is a resource exhaustion vulnerability in the mtrudel/bandit Elixir HTTP server. The flaw resides in the WebSocket fragment reassembly path inside Elixir.Bandit.WebSocket.Connection.handle_frame/3. Bandit appends every incoming Continuation{fin: false} frame to a per-connection iolist without enforcing a cumulative size cap. An unauthenticated remote peer can stream continuation frames indefinitely, growing the BEAM heap until the operating system or supervisor kills the process. Phoenix Channels and LiveView both run over WebSock on Bandit, so any stock Phoenix application that accepts socket connections exposes this attack surface. The vulnerability affects Bandit versions from 0.5.0 before 1.11.0 and is tracked under [CWE-770].

Critical Impact

Unauthenticated network attackers can exhaust server memory and crash Phoenix applications by sending a stream of WebSocket continuation frames that never set the FIN bit.

Affected Products

  • mtrudel Bandit >= 0.5.0 and < 1.11.0
  • Phoenix Channels applications running over Bandit
  • Phoenix LiveView applications running over Bandit

Discovery Timeline

  • 2026-05-01 - CVE-2026-42786 published to NVD
  • 2026-05-05 - Last updated in NVD database

Technical Details for CVE-2026-42786

Vulnerability Analysis

The vulnerability lives in lib/bandit/websocket/connection.ex. When Bandit receives a fragmented WebSocket message, handle_frame/3 accumulates each Continuation frame's payload into a per-connection iolist. The reassembly continues until a frame with fin: true arrives. The existing max_frame_size option only constrains the size of a single frame on the wire. It does not bound the aggregate size of a fragmented message.

A malicious peer can therefore send small, individually valid continuation frames in an unbounded sequence. Each frame's payload is appended to the BEAM process heap. Memory grows linearly with the number of frames sent, eventually triggering the OOM killer or supervisor termination of the connection process.

Root Cause

The accumulation occurs before WebSock.handle_in/2 is invoked. The application layer never sees the partial message and has no opportunity to interpose a size check. This violates the resource-allocation guarantees expected of a network-facing protocol parser, mapping directly to [CWE-770] Allocation of Resources Without Limits or Throttling.

Attack Vector

An unauthenticated remote attacker establishes a WebSocket connection to any endpoint served by Bandit. The attacker then transmits a continuous stream of continuation frames with fin=0 and never sends a terminating frame. Because Phoenix Channels and LiveView both rely on WebSock over Bandit, default Phoenix deployments are exposed as soon as they accept socket upgrades.

text
# Patch excerpt from lib/bandit.ex
  * `max_frame_size`: The maximum size of a single WebSocket frame (expressed as
-    a number of bytes on the wire). Defaults to 0 (no limit)
+    a number of bytes on the wire). Use a value of 0 for no limit. Defaults to 8_000_000
+  * `max_fragmented_message_size`: The maximum size of a WebSocket message delivered across
+    multiple continuation frames (expressed as a number of bytes on the wire). Does NOT affect the
+    handling of single-frame messages. Use a value of 0 for no limit. Defaults to 8_000_000

Source: GitHub Commit 21612c7

The patch introduces the new max_fragmented_message_size option and changes the default max_frame_size from unlimited to 8_000_000 bytes. The fix in lib/bandit/extractor.ex updates the default applied during parser construction:

text
   def new(frame_parser, primitive_ops_module, opts) do
-    max_frame_size = Keyword.get(opts, :max_frame_size, 0)
+    max_frame_size = Keyword.get(opts, :max_frame_size, 8_000_000)

Source: GitHub Commit 21612c7

Detection Methods for CVE-2026-42786

Indicators of Compromise

  • Sustained increases in BEAM virtual machine memory consumption tied to specific WebSocket connection PIDs.
  • WebSocket connections that remain open for extended periods while transmitting only opcode=0x0 (continuation) frames.
  • Supervisor restart events for Bandit.WebSocket.Connection processes terminated by :killed or :out_of_memory reasons.
  • Operating system OOM killer events targeting the BEAM process serving the Phoenix endpoint.

Detection Strategies

  • Instrument Bandit telemetry events such as [:bandit, :websocket, :recv] to track per-connection cumulative frame bytes and alert on sessions that exceed a defined threshold without delivering a final frame.
  • Inspect WebSocket traffic at the proxy or load balancer for connections sending many continuation frames without a corresponding FIN bit set.
  • Correlate BEAM :erlang.memory/0 snapshots with active WebSocket process counts to identify outlier connections.

Monitoring Recommendations

  • Export BEAM process memory and message queue metrics to a centralized observability platform and alert on sudden growth.
  • Monitor application logs for repeated WebSock connection terminations originating from the same client IP or token.
  • Track Phoenix endpoint connection rates and per-IP connection counts to identify abusive sources.

How to Mitigate CVE-2026-42786

Immediate Actions Required

  • Upgrade Bandit to version 1.11.0 or later, which introduces the max_fragmented_message_size cap and a non-zero default max_frame_size.
  • Audit existing Bandit configuration for explicit max_frame_size: 0 overrides and remove them or replace with a bounded value.
  • Review the GitHub Security Advisory GHSA-pf94-94m9-536p for vendor guidance.

Patch Information

The fix is delivered in Bandit 1.11.0 via commit 21612c7. It enforces a default 8 MB cap on both individual frames and reassembled fragmented messages. Operators who require larger payloads can tune the new options explicitly. Additional context is available in the CNA advisory and the OSV record.

Workarounds

  • Place a WebSocket-aware reverse proxy in front of Bandit and enforce a maximum message size at the proxy layer.
  • Apply per-connection rate limits and idle timeouts to terminate sessions that send continuation frames without making forward progress.
  • Restrict WebSocket endpoints to authenticated users where possible to reduce the unauthenticated attack surface.
bash
# Example Bandit configuration after upgrading to 1.11.0
# config/runtime.exs
config :my_app, MyAppWeb.Endpoint,
  adapter: Bandit.PhoenixAdapter,
  http: [
    websocket_options: [
      max_frame_size: 1_000_000,
      max_fragmented_message_size: 4_000_000
    ]
  ]

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

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

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.