CVE-2026-39807
Client-supplied URI scheme trusted without transport verification in bandit
Reliance on Untrusted Inputs in a Security Decision vulnerability in mtrudel bandit allows unauthenticated transport-state spoofing on plaintext HTTP connections.
'Elixir.Bandit.Pipeline':determine_scheme/2 in lib/bandit/pipeline.ex returns the client-supplied URI scheme verbatim, ignoring the transport's secure? flag. HTTP/1.1 absolute-form request targets (e.g. GET https://victim/path HTTP/1.1) and the HTTP/2 :scheme pseudo-header are both attacker-controlled strings that flow through this function. Over a plaintext TCP connection, a client can declare https and Bandit will set conn.scheme = :https even though no TLS was negotiated.
Downstream Plug consumers that branch on conn.scheme are silently misled: Plug.SSL's already-secure branch skips its HTTP→HTTPS redirect, cookies emitted with secure: true are sent over plaintext, audit logs record requests as having arrived over HTTPS, and CSRF/SameSite gating may make incorrect decisions.
This issue affects bandit: from 1.0.0 before 1.11.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- Low
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.3
Client-supplied URI scheme trusted without transport verification in bandit
Reliance on Untrusted Inputs in a Security Decision vulnerability in mtrudel bandit allows unauthenticated transport-state spoofing on plaintext HTTP connections.
'Elixir.Bandit.Pipeline':determine_scheme/2 in lib/bandit/pipeline.ex returns the client-supplied URI scheme verbatim, ignoring the transport's secure? flag. HTTP/1.1 absolute-form request targets (e.g. GET https://victim/path HTTP/1.1) and the HTTP/2 :scheme pseudo-header are both attacker-controlled strings that flow through this function. Over a plaintext TCP connection, a client can declare https and Bandit will set conn.scheme = :https even though no TLS was negotiated.
Downstream Plug consumers that branch on conn.scheme are silently misled: Plug.SSL's already-secure branch skips its HTTP→HTTPS redirect, cookies emitted with secure: true are sent over plaintext, audit logs record requests as having arrived over HTTPS, and CSRF/SameSite gating may make incorrect decisions.
This issue affects bandit: from 1.0.0 before 1.11.0.
- Record
CVE-2026-39807- CVSS 4.0
- 6.3 Medium
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 - Weakness
- CWE-807
- Updated
- 2026-11-02
EUVDEUVD-2026-26714
6.3
Reliance on Untrusted Inputs in a Security Decision vulnerability in mtrudel bandit allows unauthenticated transport-state spoofing on plaintext HTTP connections.
'Elixir.Bandit.Pipeline':determine_scheme/2 in lib/bandit/pipeline.ex returns the client-supplied URI scheme verbatim, ignoring the transport's secure? flag. HTTP/1.1 absolute-form request targets (e.g. GET https://victim/path HTTP/1.1) and the HTTP/2 :scheme pseudo-header are both attacker-controlled strings that flow through this function. Over a plaintext TCP connection, a client can declare https and Bandit will set conn.scheme = :https even though no TLS was negotiated.
Downstream Plug consumers that branch on conn.scheme are silently misled: Plug.SSL's already-secure branch skips its HTTP→HTTPS redirect, cookies emitted with secure: true are sent over plaintext, audit logs record requests as having arrived over HTTPS, and CSRF/SameSite gating may make incorrect decisions.
This issue affects bandit: from 1.0.0 before 1.11.0.
- Record
EUVD-2026-26714- CVSS 4.0
- 6.3 Medium
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 - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-375f-4r2h-f99j
6.3
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
:schemepseudo-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.SSLskipping its HTTP→HTTPS redirect because the request "already looks secure", letting plaintext requests bypass the redirect entirely.- Cookies emitted with
secure: trueon 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.schemeto 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
# 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,…
- Record
GHSA-375f-4r2h-f99j- CVSS 4.0
- 6.3 Medium
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 - Weakness
- CWE-807
- Updated
- 2026-11-02
NVD
6.3
Reliance on Untrusted Inputs in a Security Decision vulnerability in mtrudel bandit allows unauthenticated transport-state spoofing on plaintext HTTP connections.
'Elixir.Bandit.Pipeline':determine_scheme/2 in lib/bandit/pipeline.ex returns the client-supplied URI scheme verbatim, ignoring the transport's secure? flag. HTTP/1.1 absolute-form request targets (e.g. GET https://victim/path HTTP/1.1) and the HTTP/2 :scheme pseudo-header are both attacker-controlled strings that flow through this function. Over a plaintext TCP connection, a client can declare https and Bandit will set conn.scheme = :https even though no TLS was negotiated.
Downstream Plug consumers that branch on conn.scheme are silently misled: Plug.SSL's already-secure branch skips its HTTP→HTTPS redirect, cookies emitted with secure: true are sent over plaintext, audit logs record requests as having arrived over HTTPS, and CSRF/SameSite gating may make incorrect decisions.
This issue affects bandit: from 1.0.0 before 1.11.0.
- Record
CVE-2026-39807- CVSS 4.0
- 6.3 Medium
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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - Weakness
- CWE-807
- Updated
- 2026-11-02
OSV
6.3
Client-supplied URI scheme trusted without transport verification in bandit
Reliance on Untrusted Inputs in a Security Decision vulnerability in mtrudel bandit allows unauthenticated transport-state spoofing on plaintext HTTP connections.
'Elixir.Bandit.Pipeline':determine_scheme/2 in lib/bandit/pipeline.ex returns the client-supplied URI scheme verbatim, ignoring the transport's secure? flag. HTTP/1.1 absolute-form request targets (e.g. GET https://victim/path HTTP/1.1) and the HTTP/2 :scheme pseudo-header are both attacker-controlled strings that flow through this function. Over a plaintext TCP connection, a client can declare https and Bandit will set conn.scheme = :https even though no TLS was negotiated.
Downstream Plug consumers that branch on conn.scheme are silently misled: Plug.SSL's already-secure branch skips its HTTP→HTTPS redirect, cookies emitted with secure: true are sent over plaintext, audit logs record requests as having arrived over HTTPS, and CSRF/SameSite gating may make incorrect decisions.
This issue affects bandit: from 1.0.0 before 1.11.0.
- Record
CVE-2026-39807- CVSS 4.0
- 6.3 Medium
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 - Weakness
- CWE-807
- Updated
- 2026-11-02
OSVEEF-CVE-2026-39807
6.3
Client-supplied URI scheme trusted without transport verification in bandit
Summary
Reliance on Untrusted Inputs in a Security Decision vulnerability in mtrudel bandit allows unauthenticated transport-state spoofing on plaintext HTTP connections.
'Elixir.Bandit.Pipeline':determine_scheme/2 in lib/bandit/pipeline.ex returns the client-supplied URI scheme verbatim, ignoring the transport's secure? flag. HTTP/1.1 absolute-form request targets (e.g. GET https://victim/path HTTP/1.1) and the HTTP/2 :scheme pseudo-header are both attacker-controlled strings that flow through this function. Over a plaintext TCP connection, a client can declare https and Bandit will set conn.scheme = :https even though no TLS was negotiated.
Downstream Plug consumers that branch on conn.scheme are silently misled: Plug.SSL's already-secure branch skips its HTTP→HTTPS redirect, cookies emitted with secure: true are sent over plaintext, audit logs record requests as having arrived over HTTPS, and CSRF/SameSite gating may make incorrect decisions.
This issue affects bandit: from 1.0.0 before 1.11.0.
Configurations
The vulnerable system must be accepting plaintext (non-TLS) HTTP connections, either directly or via h2c. Deployments that exclusively use TLS are not affected.
- Record
EEF-CVE-2026-39807- CVSS 4.0
- 6.3 Medium
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 - Weakness
- CWE-807
- Updated
- 2026-11-02
OSVGHSA-375f-4r2h-f99j
6.3
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
:schemepseudo-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.SSLskipping its HTTP→HTTPS redirect because the request "already looks secure", letting plaintext requests bypass the redirect entirely.- Cookies emitted with
secure: trueon 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.schemeto 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
# 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,…
- Record
GHSA-375f-4r2h-f99j- CVSS 4.0
- 6.3 Medium
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 - Weakness
- CWE-807
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
banditHex |
1.0.0 up to 1.11.0 | 1.11.0 |
banditHex |
1.0.0 up to 1.11.0, plus listed versions 1.1.01.1.11.1.21.1.31.10.0 Show 35 moreShow less1.10.11.10.21.10.31.10.41.2.01.2.11.2.21.2.31.3.01.4.01.4.11.4.21.5.01.5.11.5.21.5.31.5.41.5.51.5.61.5.71.6.01.6.11.6.101.6.111.6.21.6.31.6.41.6.51.6.61.6.71.6.81.6.91.7.01.8.01.9.0 |
1.11.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-39807 is a medium vulnerability (CVSS 6.3) in Mtrudel Bandit, published May 1, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.53%, the 45th percentile. Fixed in bandit 1.11.0.
References
Left out here: the rest of 2 source descriptions. The JSON record has them.