Skip to content

EEF-CVE-2026-110314 CVE-2026-110314 GHSA-2v5v-8f9v-xh85

WebSocket frames keep reaching the WebSock after a server-initiated close in Bandit

Not rated yet Hex
Severity
0.0 / 10
Unknown · CVSS 4.0
Exploit chance (EPSS)
0.38%
Chance of exploitation in the next 30 days. Higher than 32.45% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-602 Client-Side Enforcement of Server-Side Security
Fix
1.14.0
Upgrade bandit to this version or later

Description

Summary

Client-Side Enforcement of Server-Side Security vulnerability in the WebSocket connection handling of mtrudel bandit allows a remote client to keep running WebSock handler code after the server has stopped its connection, via data frames sent after ignoring the server's Close frame.

When a WebSock callback returns {:stop, ...}, Bandit.WebSocket.Connection calls terminate/2, sends Close and shuts down the write side, but keeps the connection process running in a :closing state. handle_frame/3 and handle_info/3 never check that state, so later frames still reach handle_in/2 and later messages reach handle_info/2, with the state from the stop tuple, until the client sends Close, TCP drops or the idle timeout fires. A client refused in init/1 after a failed token check could still run an admin-only action.

This issue affects bandit: from 0.5.1 before 1.14.0.

Details

1. Stop without close. In Bandit.WebSocket.Connection, do_stop/4 calls terminate/2, sends the Close frame and runs shutdown(:write). It then returns {:continue, %{connection | state: :closing}}, so Bandit.WebSocket.Handler keeps the process alive.

2. No state check. handle_frame/3 and handle_info/3 never check connection.state. Every later data frame still reaches handle_in/2, and every later message still reaches handle_info/2, with the state from the stop tuple.

3. Client-controlled lifetime. The connection ends only when the client sends Close, TCP drops, or the idle timeout fires, and each client frame resets that timeout. All stops through do_stop are affected: {:stop, :normal, ...}, {:stop, {:shutdown, :disconnected}, ...} and {:stop, {:shutdown, :restart}, ...}, which is what Phoenix's :socket_drain returns. A banned user who was kicked kept posting for longer than the idle timeout.

Proof of concept

  1. Serve a WebSock whose init/1 returns {:stop, :normal, {4401, "unauthorized"}, state} for a wrong token, and whose handle_in/2 runs an admin-only delete_all_users action when user_id is admin.
  2. Upgrade with ?user_id=admin&token=wrong. The server calls terminate/2 and sends a Close frame with code 4401.
  3. Ignore the Close frame and send a masked text frame delete_all_users.
  4. handle_in/2 runs delete_all_users as admin.

Impact

A remote client that ignores the Close frame can keep invoking a WebSock application's handlers after the application refused or ended its session, bypassing an authorization check in init/1 or a kick or ban. This affects WebSock applications that rely on {:stop, ...} to end a session.

Workarounds

Mark the WebSock state as stopped whenever a callback returns {:stop, ...}, and have handle_in/2 and handle_info/2 return {:ok, state} without acting while that mark is set.

Affected versions

Hex

PackageVulnerableFixed in
bandit
>= 0.5.1, < 1.14.0
1.14.0

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

bandit Hex → 1.14.0

mix
{:bandit, "~> 1.14.0"} # then: mix deps.update bandit

Severity breakdown

CVSS 4.0 0.0

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N

Attack vector
Network
Attack complexity
Low
Attack requirements
Present
Privileges required
None
User interaction
None
Confidentiality (vulnerable system)
Low
Integrity (vulnerable system)
Low
Availability (vulnerable system)
None
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None

Weakness

CWE-602: Client-Side Enforcement of Server-Side Security

The product is composed of a server that relies on the client to implement a mechanism that is intended to protect the server.

How to prevent it
  • Architecture and Design: For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server. Even though client-side checks provide minimal benefits with respect to server-side security, they are still useful. First, they can support intrusion detection. If the server receives input that should have been rejected by the client, then it may be an indication of an attack. Second, client-side error-checking can provide helpful feedback to the user about the expectations for valid input. Third, there may be a reduction in server-side processing time for accidental input errors, although this is typically a small savings.
  • Architecture and Design: If some degree of trust is required between the two entities, then use integrity checking and strong authentication to ensure that the inputs are coming from a trusted source. Design the product so that this trust is managed in a centralized fashion, especially if there are complex or numerous communication channels, in order to reduce the risks that the implementer will mistakenly omit a check in a single code path.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
EEF-CVE-2026-116078
HTTP/2 request bodies made of 1-byte DATA frames amplify memory use in Bandit
Not rated yet Also affects bandit
EEF-CVE-2026-108529
SETTINGS and stream-0 WINDOW_UPDATE frames trigger quadratic work over blocked streams in Bandit
Not rated yet Also affects bandit
EEF-CVE-2026-110499
Client-chosen HPACK encoder table size is applied uncapped, growing per-connection state with every response in Bandit
Not rated yet Also affects bandit
EEF-CVE-2026-109584
HTTP/2 cookie crumb join expands a small HPACK header block into an unbounded allocation in Bandit
Not rated yet Also affects bandit
EEF-CVE-2026-111103
HTTP/2 StreamError recovery rolls back connection state and bypasses per-connection limits in Bandit
Not rated yet Also affects bandit
EEF-CVE-2026-111101
HTTP/1.1 chunked request bodies made of 1-byte chunks amplify memory use in Bandit
Not rated yet Also affects bandit
EEF-CVE-2026-113436
Quadratic bignum parsing of Content-Length and Host port values in Bandit
Not rated yet Also affects bandit
EEF-CVE-2026-114213
WebSocket 1-byte continuation frames bypass `max_fragmented_message_size` in Bandit
Not rated yet Also affects bandit

Credits: Jonatan Männchen / EEF, Mat Trudel, Peter Ullrich

Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor