Moderate severityNVD Advisory· Published Aug 25, 2015· Updated May 6, 2026
CVE-2015-4020
CVE-2015-4020
Description
RubyGems 2.0.x before 2.0.17, 2.2.x before 2.2.5, and 2.4.x before 2.4.8 does not validate the hostname when fetching gems or making API requests, which allows remote attackers to redirect requests to arbitrary domains via a crafted DNS SRV record with a domain that is suffixed with the original domain name, aka a "DNS hijack attack." NOTE: this vulnerability exists because to an incomplete fix for CVE-2015-3900.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
rubygems-updateRubyGems | < 2.0.17 | 2.0.17 |
rubygems-updateRubyGems | >= 2.1.0.rc.1, < 2.2.5 | 2.2.5 |
rubygems-updateRubyGems | >= 2.3.0, < 2.4.8 | 2.4.8 |
Affected products
36cpe:2.3:a:rubygems:rubygems:2.0.0:*:*:*:*:*:*:*+ 34 more
- cpe:2.3:a:rubygems:rubygems:2.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.0:preview2:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.0:preview2.1:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.0:preview2.2:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.0:rc1:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.0:rc2:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.10:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.11:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.12:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.13:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.14:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.15:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.16:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.2:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.3:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.4:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.5:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.6:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.7:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.8:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.0.9:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.2.0:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.2.1:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.2.2:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.2.3:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.2.4:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.0:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.1:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.2:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.3:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.4:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.5:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.6:*:*:*:*:*:*:*
- cpe:2.3:a:rubygems:rubygems:2.4.7:*:*:*:*:*:*:*
- cpe:2.3:o:oracle:solaris:11.3:*:*:*:*:*:*:*
Patches
15c7bfb5Fix API endpoint domain clamping
2 files changed · +31 −1
lib/rubygems/remote_fetcher.rb+1 −1 modified@@ -96,7 +96,7 @@ def api_endpoint(uri) else target = res.target.to_s.strip - if /#{host}\z/ =~ target + if /\.#{Regexp.quote(host)}\z/ =~ target return URI.parse "#{uri.scheme}://#{target}#{uri.path}" end
test/rubygems/test_gem_remote_fetcher.rb+30 −0 modified@@ -196,6 +196,36 @@ def test_api_endpoint_ignores_trans_domain_values dns.verify end + def test_api_endpoint_ignores_trans_domain_values_that_starts_with_original + uri = URI.parse "http://example.com/foo" + target = MiniTest::Mock.new + target.expect :target, "example.combadguy.com" + + dns = MiniTest::Mock.new + dns.expect :getresource, target, [String, Object] + + fetch = Gem::RemoteFetcher.new nil, dns + assert_equal URI.parse("http://example.com/foo"), fetch.api_endpoint(uri) + + target.verify + dns.verify + end + + def test_api_endpoint_ignores_trans_domain_values_that_end_with_original + uri = URI.parse "http://example.com/foo" + target = MiniTest::Mock.new + target.expect :target, "badexample.com" + + dns = MiniTest::Mock.new + dns.expect :getresource, target, [String, Object] + + fetch = Gem::RemoteFetcher.new nil, dns + assert_equal URI.parse("http://example.com/foo"), fetch.api_endpoint(uri) + + target.verify + dns.verify + end + def test_cache_update_path uri = URI 'http://example/file' path = File.join @tempdir, 'file'
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
14- blog.rubygems.org/2015/06/08/2.2.5-released.htmlnvdVendor AdvisoryWEB
- blog.rubygems.org/2015/06/08/2.4.8-released.htmlnvdVendor AdvisoryWEB
- www.oracle.com/technetwork/topics/security/bulletinoct2015-2511968.htmlnvdThird Party AdvisoryWEB
- github.com/advisories/GHSA-qv62-xfj6-32xmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2015-4020ghsaADVISORY
- www.trustwave.com/Resources/Security-Advisories/Advisories/TWSL2015-009/nvdThird Party AdvisoryWEB
- www.trustwave.com/Resources/SpiderLabs-Blog/Attacking-Ruby-Gem-Security-with-CVE-2015-3900/nvdThird Party Advisory
- www.securityfocus.com/bid/75431nvdWEB
- github.com/rubygems/rubygems/commit/5c7bfb5nvdWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/rubygems-update/CVE-2015-4020.ymlghsaWEB
- puppet.com/security/cve/CVE-2015-3900nvdWEB
- web.archive.org/web/20200228084212/http://www.securityfocus.com/bid/75431ghsaWEB
- web.archive.org/web/20200228085830/https://puppet.com/security/cve/CVE-2015-3900ghsaWEB
- www.trustwave.com/Resources/SpiderLabs-Blog/Attacking-Ruby-Gem-Security-with-CVE-2015-3900ghsaWEB
News mentions
0No linked articles in our index yet.