Bandit, Scheme Spoofing Vulnerability, Medium

Listen to this Post

The vulnerability exists in Bandit’s `determine_scheme/2` function (lib/bandit/pipeline.ex, line ~89). It takes two inputs: the client-supplied scheme from the request target (HTTP/1.1 absolute-form or HTTP/2 `:scheme` pseudo-header) and the transport’s `secure?` flag (true for TLS, false for plaintext). The function uses pattern matching: `{_, scheme} -> scheme` as the third clause. This clause returns the client’s scheme verbatim and discards the `secure?` flag entirely. An attacker on a plaintext TCP connection (or h2c) sends an absolute-form request like GET https://victim/path HTTP/1.1. Bandit parses the scheme `https` but never validates it against the actual non‑TLS socket. Since `secure?` is ignored, the resulting `%Plug.Conn{scheme: :https}` is built and passed to the Plug stack. No guard or sanitisation prevents this. The bug was introduced on Jun 8, 2023 (commit ff2f829). A fixed server would either force scheme to `:http` when `secure?` is false, or reject the request with 400 Bad Request. Bandit 1.10.4 returns `:https` on a plaintext socket, as confirmed by the PoC script.

dailycve form:

Platform: Bandit HTTP server
Version: Up to 1.10.4
Vulnerability : Scheme spoofing bug
Severity: Medium
date: 8 June 2023

Prediction: Expected patch 2023-06-15

What Undercode Say:

Test for scheme spoofing
echo -e "GET https://localhost:4321/ HTTP/1.1\r\nHost: localhost:4321\r\nConnection: close\r\n\r\n" | nc localhost 4321
Check response body for conn.scheme value
Elixir reproduction (mix run)
Mix.install([{:bandit, "~> 1.10"}, {:plug, "~> 1.19"}])
defmodule Test do
def run do
{:ok, _} = Bandit.start_link(plug: fn conn, _ -> send_resp(conn, 200, inspect(conn.scheme)) end, port: 4321)
{:ok, s} = :gen_tcp.connect('localhost', 4321, [:binary])
:gen_tcp.send(s, "GET https://localhost:4321/ HTTP/1.1\r\nHost: localhost:4321\r\n\r\n")
IO.puts(elem(:gen_tcp.recv(s, 0), 1))
end
end
Test.run()

How Exploit:

Send HTTP/1.1 absolute-form request with `https` scheme over plaintext socket. For h2c, set `:scheme` pseudo-header to https. No authentication required. Server returns conn.scheme=:https, misleading all downstream security logic.

Protection from this CVE:

Upgrade Bandit to patched version (fix commit changes `determine_scheme/2` to ignore client scheme and use only secure?). If patching impossible, reject requests with absolute-form targets or `:scheme` mismatching transport. Use reverse proxy (e.g., nginx) to terminate plaintext and normalise scheme.

Impact:

Attacker bypasses Plug.SSL redirect (plaintext stays unencrypted), reads `secure: true` cookies over network, poisons audit logs, and defeats CSRF/SameSite or OAuth redirect decisions that trust conn.scheme. Full transport‑state spoofing for any plaintext listener.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top