VYPR
None severity0.0GHSA Advisory· Published May 19, 2026· Updated May 19, 2026

CVE-2026-33637

CVE-2026-33637

Description

Faraday is an HTTP client library abstraction layer that provides a common interface over many adapters. Versions 2.0.0 through 2.14.1 still allow protocol-relative host override when the request target is passed as a URI object (rather than a String) to Faraday::Connection#build_exclusive_url. This bypasses the February 2026 fix for GHSA-33mh-2634-fwr2 and enables off-host request forgery: a request built from a fixed-base Faraday::Connection can be redirected to an attacker-controlled host, forwarding connection-scoped values such as Authorization headers and default query parameters. This issue has been fixed in version 2.14.3.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Faraday 2.0.0–2.14.1 allows protocol-relative URI objects to override the connection's host, bypassing a previous fix and enabling off-host request forgery.

Vulnerability

Faraday versions 2.0.0 through 2.14.1 contain an incomplete fix for GHSA-33mh-2634-fwr2 (CVE-2026-25765). The Faraday::Connection#build_exclusive_url method still permits protocol-relative host override when the request target is provided as a URI object (e.g., URI("//evil.example/pwn")) rather than a String. This bypasses the ./ prefix guard added in v2.9.2 and allows the request to be redirected to an attacker-controlled host while preserving connection-scoped values such as Authorization headers and default query parameters [1][2][4].

Exploitation

An attacker who can influence a per-request target/path in an application that uses a fixed-base Faraday::Connection can supply a protocol-relative URI object. For example, if the application converts user input to URI.parse(...) and passes it to conn.get(...), conn.post(...), or req.url(...), the attacker can provide URI("//evil.example/pwn"). The request is then sent to the attacker-controlled host instead of the configured base host, and connection-scoped headers (e.g., Authorization) are forwarded [1][2].

Impact

Successful exploitation results in off-host request forgery. The attacker can cause the server to make HTTP requests to an arbitrary host, potentially leaking sensitive connection-scoped data such as authentication tokens or API keys. This constitutes a Server-Side Request Forgery (SSRF) vulnerability, with the added risk of credential exposure [1][2][4].

Mitigation

The issue is fixed in Faraday version 2.14.3 [1][2]. Users should upgrade to 2.14.3 or later. If upgrading is not immediately possible, applications should validate and sanitize any user-controlled input before passing it to Faraday request methods, specifically rejecting or stripping input that starts with // followed by a non-/ character, or using an allowlist of permitted path prefixes [4]. No workaround is provided in the advisory for the URI object bypass, so upgrading is strongly recommended.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

1
3f1280c69e93

Merge commit from fork

https://github.com/lostisland/faradayTomoya YamashitaMay 15, 2026Fixed in 2.14.2via llm-release-walk
4 files changed · +21 3
  • lib/faraday/connection.rb+3 1 modified
    @@ -481,9 +481,11 @@ def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
           if url && !base.path.end_with?('/')
             base.path = "#{base.path}/" # ensure trailing slash
           end
    +      url = url.to_s if url.respond_to?(:host)
           # Ensure relative url will be parsed correctly (such as `service:search` or `//evil.com`)
           url = "./#{url}" if url.respond_to?(:start_with?) &&
    -                          (!url.start_with?('http://', 'https://', '/', './', '../') || url.start_with?('//'))
    +                          (url.start_with?('//') ||
    +                           !url.start_with?('http://', 'https://', '/', './', '../'))
           uri = url ? base + url : base
           if params
             uri.query = params.to_query(params_encoder || options.params_encoder)
    
  • .rubocop_todo.yml+2 2 modified
    @@ -38,12 +38,12 @@ Metrics/AbcSize:
     # Offense count: 4
     # Configuration parameters: CountComments, CountAsOne.
     Metrics/ClassLength:
    -  Max: 231
    +  Max: 233
     
     # Offense count: 8
     # Configuration parameters: AllowedMethods, AllowedPatterns.
     Metrics/CyclomaticComplexity:
    -  Max: 13
    +  Max: 14
     
     # Offense count: 28
     # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
    
  • spec/faraday/connection_spec.rb+7 0 modified
    @@ -318,6 +318,13 @@ def decode(params)
             expect(uri.host).to eq('httpbingo.org')
           end
     
    +      it 'does not allow host override with URI("//evil.com/path")' do
    +        conn.url_prefix = 'http://httpbingo.org/api'
    +        uri = conn.build_exclusive_url(URI('//evil.com/path?token=1'))
    +        expect(uri.host).to eq('httpbingo.org')
    +        expect(uri.query).to eq('token=1')
    +      end
    +
           it 'does not allow host override with //evil.com:8080/path' do
             conn.url_prefix = 'http://httpbingo.org/api'
             uri = conn.build_exclusive_url('//evil.com:8080/path')
    
  • spec/faraday/request_spec.rb+9 0 modified
    @@ -31,6 +31,15 @@
         it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
       end
     
    +  context 'when setting the url on setup with a protocol-relative URI' do
    +    let(:block) { proc { |req| req.url URI.parse('//evil.com/path?token=1') } }
    +    let(:url) { subject.to_env(conn).url }
    +
    +    it { expect(url.host).to eq('httpbingo.org') }
    +    it { expect(url.path).to eq('/api///evil.com/path') }
    +    it { expect(url.query).to eq('token=1') }
    +  end
    +
       context 'when setting the url on setup with a string path and params' do
         let(:block) { proc { |req| req.url 'foo.json', 'a' => 1 } }
     
    

Vulnerability mechanics

Root cause

"Missing conversion of URI object to string before protocol-relative host override check allows bypass of SSRF protection."

Attack vector

An attacker who can control the URL passed to `Faraday::Connection#build_exclusive_url` as a URI object (e.g., via `URI.parse('//evil.com/path')`) can override the host of a request built from a fixed-base connection. The protocol-relative URI `//evil.com/path` is not caught by the existing `start_with?` checks because those checks operate on the URI object's `to_s` representation only after the host-override logic has already been applied. This enables off-host request forgery, where connection-scoped values such as Authorization headers and default query parameters are forwarded to the attacker-controlled host [CWE-918].

Affected code

The vulnerability resides in `lib/faraday/connection.rb` within the `build_exclusive_url` method. When a URI object (rather than a String) is passed as the `url` argument, the method does not convert it to a string before the protocol-relative host override check. This allows a URI like `//evil.com/path` to bypass the guard that was added in the February 2026 fix for GHSA-33mh-2634-fwr2.

What the fix does

The patch adds `url = url.to_s if url.respond_to?(:host)` at the top of `build_exclusive_url`, converting any URI object to a plain string before the host-override guard logic runs [patch_id=898946]. It also restructures the `start_with?` condition to explicitly check for `'//'` first, ensuring protocol-relative URIs are always prefixed with `'./'` to prevent host hijacking. The accompanying spec tests verify that passing `URI('//evil.com/path?token=1')` preserves the original connection host (`httpbingo.org`) and treats the input as a relative path.

Preconditions

  • inputThe attacker must be able to supply a URI object (not a string) as the URL argument to Faraday::Connection#build_exclusive_url.
  • configThe Faraday::Connection must have a fixed base URL (url_prefix) set.

Generated on May 20, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.