Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-39807 — bandit

⚪ Unknown ✅ No Known Exploit CWE-807 NVD
N/A
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Bandit trusts client-supplied URI scheme on plaintext connections

Summary

Bandit reflects the client-supplied URI scheme into conn.scheme without verifying the actual transport. Over a plaintext HTTP/1.1 connection (or h2c), an unauthenticated attacker can send an absolute-form request target like GET https://victim/path HTTP/1.1 and the application observes conn.scheme = :https even though no TLS was negotiated. Any downstream Plug logic that trusts conn.scheme as a security signal — Plug.SSL's "already secure, don't redirect" branch, secure: true cookie flagging, audit logging, CSRF/SameSite gating — is silently misled into treating an attacker's plaintext connection as encrypted.

The vulnerability was introduced on Jun 8, 2023: https://github.com/mtrudel/bandit/commit/ff2f829326cd5dcf7335939aef9775269d881e28

Details

The bug is in lib/bandit/pipeline.ex at determine_scheme/2 (around line 89). The function takes the request target's scheme and the transport's secure? flag and produces the URI scheme used to build the %Plug.Conn{}. The third match clause is {_, scheme} -> scheme — i.e. whenever the client supplies *any* scheme on the request target, the function returns that scheme verbatim and discards secure? entirely.

Two attacker-controlled inputs reach this code path:

  • HTTP/1.1 absolute-form request targets (RFC 9112 §3.2.2), e.g. GET https://victim/path HTTP/1.1.
  • HTTP/2 :scheme pseudo-header, which is a free-form string sent by the client.

Neither value is constrained to match the actual transport. On a plaintext TCP listener (or h2c), a client can declare https and Bandit will pass %URI{scheme: "https"} into Plug.Conn.Adapter.conn/5, producing conn.scheme == :https. There is no guard in determine_scheme/2; the discarding of secure? is deliberate.

Suggested fix: when secure? is true, force the scheme to "https"; when false, force it to "http" — or reject the request with 400 Bad Request if the supplied scheme disagrees with the transport's actual security state. Do not trust the client-supplied scheme.

PoC

A self-contained reproduction script is available below. It starts plaintext Bandit 1.10 on 127.0.0.1:4321 with a Plug that echoes conn.scheme, opens a plain TCP socket, and sends:

```

GET https://127.0.0.1:4321/ HTTP/1.1

Host: 127.0.0.1:4321

Connection: close

```

A correctly-behaving server would either coerce conn.scheme to :http or return 400 Bad Request. Bandit 1.10.4 returns :https, confirming the spoof.

Impact

Transport-state spoofing. Any unauthenticated client speaking plaintext HTTP/1.1 or h2c to a Bandit endpoint can cause the application to treat the connection as if it had been TLS-protected. Concrete consequences in real Phoenix/Plug stacks include:

  • Plug.SSL skipping its HTTP→HTTPS redirect because the request "already looks secure", letting plaintext requests bypass the redirect entirely.
  • Cookies emitted with secure: true on a plaintext response, where a network attacker could capture them.
  • Audit logs recording requests as having arrived over HTTPS when they did not, breaking forensic and compliance assumptions.
  • Application code that uses conn.scheme to gate CSRF/SameSite policy, OAuth redirect URIs, or HSTS-related decisions making the wrong call.

The vulnerability is unauthenticated and trivially automatable; severity is medium because exploitation requires the deployment to expose a plaintext Bandit listener (or h2c) and to have downstream code that branches on conn.scheme.

Script and Logs

```elixir

# Bandit reflects the client-supplied scheme into conn.scheme.

#

# lib/bandit/pipeline.ex:89 (determine_scheme/2) returns whatever scheme

# appears on the request target, ignoring the secure? flag that records

# the actual transport state. HTTP/1.1 absolute-form request targets

# (e.g. GET https://victim/path HTTP/1.1) and HTTP/2 :scheme are both

# attacker-controlled strings that flow into this function. Over a

# plaintext connection, a client can claim https and Bandit hands a

# %Plug.Conn{scheme: :https} to the application — even though no TLS

# was negotiated.

#

# Downstream Plug consumers that branch on conn.scheme are misled:

# Plug.SSL's "already secure, don't redirect" path, secure: true cookie

# flagging, audit logs, CSRF/SameSite gating, etc.

#

# This script starts plaintext Bandit 1.10 on 127.0.0.1:4321, sends one

# HTTP/1.1 absolute-form request with scheme https://, and prints the

# conn.scheme the application observes. A fixed server should report

# :http (or reject the request); the buggy server reports :https.

#

# Run: elixir scripts/bandit/http1_scheme_spoofing.exs

Mix.install([

{:bandit, "~> 1.10"},

{:plug, "~> 1.19"}

])

defmodule SchemeApp do

@behaviour Plug

def init(opts), do: opts

def call(conn, _opts) do

body = "This is what the Plug sees: conn.scheme=#{inspect(conn.scheme)}\n"

Plug.Conn.send_resp(conn, 2

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. Rated impact: confidentiality low, integrity low, availability none.

CVSS metrics in full

The score comes from this vector: 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 — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Attack requirements: Present — the target has to be in a particular state for the attack to work.
  • Privileges required: None — an unauthenticated stranger can try it.
  • User interaction: None — nobody has to be tricked into anything.
  • Confidentiality impact: Low — limited, and the attacker does not choose what is affected.
  • Integrity impact: Low — limited, and the attacker does not choose what is affected.
  • Availability impact: None.

Weakness class

CVE-2026-39807 is classified as CWE-807: Reliance on Untrusted Inputs in a Security Decision. The product uses a protection mechanism that relies on the existence or values of an input, but the input can be modified by an untrusted actor in a way that bypasses the protection mechanism.

Affected software

CVE-2026-39807 is recorded against 2 packages.

  • bandit
  • unknown

Timeline and source

Published on 1 May 2026 and last revised on 30 July 2026. No public exploit is currently recorded for this entry. A vendor advisory or fix has been published. Record sourced from NVD.

References

github.com (Advisory)
cna.erlef.org (Web)
github.com (Fix)
hex.pm (Package)

Other advisories for this package

bandit has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-807: Reliance on Untrusted Inputs in a Security Decision) in other software:

Details

Severity Unknown
CVSS Score N/A
CVSS Vector 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
CWE CWE-807
Public Exploit ✅ No
Source NVD
Published 2026-05-01
Updated 2026-08-20
Modified 2026-07-30

Affected Packages

Software From version Fixed in
bandit
unknown

Similar Threats

Free Vulnerability Check

Is your site affected by CVE-2026-39807?

BotEraser helps you identify potentially vulnerable plugins and themes by checking your installation against CVE-2026-39807 and other known CVE records.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026