High severity8.2NVD Advisory· Published Dec 23, 2025· Updated Apr 29, 2026
CVE-2025-68696
CVE-2025-68696
Description
httparty is an API tool. In versions 0.23.2 and prior, httparty is vulnerable to SSRF. This issue can pose a risk of leaking API keys, and it can also allow third parties to issue requests to internal servers. This issue has been patched via commit 0529bcd.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
httpartyRubyGems | < 0.24.0 | 0.24.0 |
Affected products
1Patches
10529bcd6309cfix: prevent SSRF via absolute URL bypassing base_uri (GHSA-hm5p-x4rq-38w4)
4 files changed · +95 −1
lib/httparty/exceptions.rb+4 −0 modified@@ -59,4 +59,8 @@ class DuplicateLocationHeader < ResponseError; end # Exception that is raised when common network errors occur. class NetworkError < Foul; end + + # Exception that is raised when an absolute URI is used that doesn't match + # the configured base_uri, which could indicate an SSRF attempt. + class UnsafeURIError < Foul; end end
lib/httparty/request.rb+20 −0 modified@@ -113,6 +113,8 @@ def uri new_uri = path.clone end + validate_uri_safety!(new_uri) unless redirect + # avoid double query string on redirects [#12] unless redirect new_uri.query = query_string(new_uri) @@ -442,5 +444,23 @@ def encode_text(text, content_type) assume_utf16_is_big_endian: assume_utf16_is_big_endian ).call end + + def validate_uri_safety!(new_uri) + return if options[:skip_uri_validation] + + configured_base_uri = options[:base_uri] + return unless configured_base_uri + + normalized_base = options[:uri_adapter].parse( + HTTParty.normalize_base_uri(configured_base_uri) + ) + + return if new_uri.host == normalized_base.host + + raise UnsafeURIError, + "Requested URI '#{new_uri}' has host '#{new_uri.host}' but the " \ + "configured base_uri '#{normalized_base}' has host '#{normalized_base.host}'. " \ + "This request could send credentials to an unintended server." + end end end
spec/httparty/request_spec.rb+68 −0 modified@@ -384,6 +384,74 @@ end end end + + context "URI safety validation" do + context "when base_uri is configured" do + it "raises UnsafeURIError when path is an absolute URL with different host" do + request = HTTParty::Request.new( + Net::HTTP::Get, + 'http://evil.com/steal-data', + base_uri: 'http://trusted.com' + ) + expect { request.uri }.to raise_error( + HTTParty::UnsafeURIError, + /has host 'evil.com' but the configured base_uri .* has host 'trusted.com'/ + ) + end + + it "allows requests when path host matches base_uri host" do + request = HTTParty::Request.new( + Net::HTTP::Get, + 'http://trusted.com/api/data', + base_uri: 'http://trusted.com' + ) + expect { request.uri }.not_to raise_error + expect(request.uri.host).to eq('trusted.com') + end + + it "allows relative paths" do + request = HTTParty::Request.new( + Net::HTTP::Get, + '/api/data', + base_uri: 'http://trusted.com' + ) + expect { request.uri }.not_to raise_error + expect(request.uri.to_s).to eq('http://trusted.com/api/data') + end + + it "raises UnsafeURIError for network-relative URLs with different host" do + @request.last_uri = URI.parse("https://trusted.com") + @request.path = URI.parse("//evil.com/steal") + @request.redirect = true + @request.options[:base_uri] = 'http://trusted.com' + + # During redirects, URI safety is not checked to allow legitimate redirects + expect { @request.uri }.not_to raise_error + end + + it "can be bypassed with skip_uri_validation option" do + request = HTTParty::Request.new( + Net::HTTP::Get, + 'http://other.com/api/data', + base_uri: 'http://trusted.com', + skip_uri_validation: true + ) + expect { request.uri }.not_to raise_error + expect(request.uri.host).to eq('other.com') + end + end + + context "when base_uri is not configured" do + it "allows absolute URLs" do + request = HTTParty::Request.new( + Net::HTTP::Get, + 'http://any-server.com/api/data' + ) + expect { request.uri }.not_to raise_error + expect(request.uri.host).to eq('any-server.com') + end + end + end end describe "#setup_raw_request" do
spec/support/stub_response.rb+3 −1 modified@@ -29,7 +29,9 @@ def response.read_body(&block) def stub_response(body, code = '200') code = code.to_s - @request.options[:base_uri] ||= 'http://localhost' + # Only set default base_uri if path is relative (has no host) + # This avoids triggering URI safety validation for absolute URLs in tests + @request.options[:base_uri] ||= 'http://localhost' if @request.path.relative? unless defined?(@http) && @http @http = Net::HTTP.new('localhost', 80) allow(@request).to receive(:http).and_return(@http)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/jnunemaker/httparty/commit/0529bcd6309c9fd9bfdd50ae211843b10054c240nvdPatchWEB
- github.com/jnunemaker/httparty/security/advisories/GHSA-hm5p-x4rq-38w4nvdExploitVendor AdvisoryWEB
- github.com/advisories/GHSA-hm5p-x4rq-38w4ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-68696ghsaADVISORY
- github.com/rubysec/ruby-advisory-db/blob/master/gems/httparty/CVE-2025-68696.ymlghsaWEB
News mentions
0No linked articles in our index yet.