CVE-2026-39806 Overview
CVE-2026-39806 is an infinite loop vulnerability [CWE-835] in the mtrudel Bandit HTTP server for Elixir. The flaw resides in the chunked transfer encoding parser and allows unauthenticated remote attackers to exhaust the Bandit worker pool. A handful of concurrent connections sending RFC 9112 conformant chunked requests with trailer fields is enough to render the server unresponsive. The issue affects Bandit versions from 1.6.1 before 1.11.1. Servers deployed behind reverse proxies such as NGINX or HAProxy may be impacted by legitimate, non-malicious traffic because those proxies forward trailer-bearing requests.
Critical Impact
Unauthenticated attackers can pin every Bandit worker process indefinitely, producing a complete denial of service against the HTTP service without authentication, special headers, or large payloads.
Affected Products
- mtrudel Bandit 1.6.1 through versions prior to 1.11.1
- Elixir/Phoenix applications using Bandit as the HTTP server
- Deployments behind RFC-compliant proxies (NGINX, HAProxy) that forward HTTP trailers
Discovery Timeline
- 2026-05-13 - CVE-2026-39806 published to NVD
- 2026-05-13 - Last updated in NVD database
Technical Details for CVE-2026-39806
Vulnerability Analysis
The defect lives in Elixir.Bandit.HTTP1.Socket.do_read_chunked_data!/5 within lib/bandit/http1/socket.ex. The function processes the terminating sequence of an HTTP/1.1 chunked-encoded body. It only terminates correctly when the last-chunk line 0\r\n is followed immediately by the empty trailer line \r\n. RFC 9112 §7.1.2, however, permits zero or more trailer fields between these markers, and Bandit's match clauses do not handle that legitimate case.
When trailer fields are present, none of the function's pattern match clauses fit. Execution falls through to the catch-all arm, which computes a negative to_read value, invokes read_available!/2, receives an empty binary <<>> on timeout, and tail-recurses with unchanged state. The worker process is pinned for the lifetime of the TCP connection.
Root Cause
The root cause is incomplete protocol parsing of the chunked transfer-encoding trailer section. The implementation assumed the trailer block is always empty, omitting the RFC-permitted trailer-field lines between the last chunk and the closing CRLF. The catch-all clause silently degrades to an unproductive loop instead of raising an error or advancing the parser state.
Attack Vector
An unauthenticated remote attacker opens several concurrent TCP connections to the target. Each connection sends a valid HTTP/1.1 request with Transfer-Encoding: chunked, terminating the body with 0\r\n, one or more trailer fields, and a final \r\n. Each connection captures one Bandit worker for the duration of the TCP session. With only a small number of parallel connections the worker pool is fully consumed, and all subsequent requests, including legitimate traffic, fail. The attack does not require authentication, large payloads, or any non-standard headers. Refer to the GitHub Security Advisory GHSA-rf5q-vwxw-gmrf for further technical context.
Detection Methods for CVE-2026-39806
Indicators of Compromise
- Sustained Bandit worker saturation accompanied by long-lived TCP connections from a small set of source addresses
- Inbound HTTP/1.1 requests containing Transfer-Encoding: chunked and trailer fields that do not match expected application traffic patterns
- Elixir/BEAM process counts plateauing at the configured Bandit worker maximum while CPU remains idle
Detection Strategies
- Inspect HTTP access logs and proxy logs for requests carrying chunked bodies with trailer headers, correlating against client IPs producing repeated long-lived connections
- Monitor BEAM telemetry for stalled Bandit acceptor processes and rising message-queue lengths on Bandit.HTTP1.Socket workers
- Alert when concurrent active connections approach the configured Bandit worker pool ceiling without proportional request throughput
Monitoring Recommendations
- Track Bandit worker pool utilization and HTTP request completion rates as baseline service-health metrics
- Capture and review trailer headers at the reverse proxy layer, where NGINX or HAProxy can be configured to log $http_trailer or equivalent fields
- Configure aggressive idle-connection timeouts at the proxy and load-balancer tier to bound worker hold time
How to Mitigate CVE-2026-39806
Immediate Actions Required
- Upgrade Bandit to version 1.11.1 or later in all Elixir and Phoenix deployments
- Audit dependency lockfiles such as mix.lock for transitively pinned Bandit versions in the 1.6.1 to 1.11.0 range
- Restart application nodes after upgrade to ensure no pinned worker processes remain from prior exploitation attempts
Patch Information
The fix is delivered in Bandit 1.11.1. The corrective change is published in the upstream repository as commit ae3520dfdbfab115c638f8c7f6f6b805db34e1ab, which extends do_read_chunked_data!/5 to accept RFC 9112 conformant trailer fields between the last-chunk marker and the closing CRLF. Additional advisory detail is available from the Erlang Ecosystem Foundation CNA and the OSV entry EEF-CVE-2026-39806.
Workarounds
- Configure the upstream reverse proxy to strip HTTP trailers before forwarding requests to Bandit, where supported
- Enforce short read and idle timeouts at the proxy layer to forcibly close stalled connections that would otherwise pin Bandit workers
- Rate-limit concurrent connections per source IP at the proxy or firewall to reduce the impact of a small number of malicious clients
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

