VYPR
Moderate severityNVD Advisory· Published Mar 15, 2021· Updated Aug 3, 2024

CVE-2021-28363

CVE-2021-28363

Description

The urllib3 library 1.26.x before 1.26.4 for Python omits SSL certificate validation in some cases involving HTTPS to HTTPS proxies. The initial connection to the HTTPS proxy (if an SSLContext isn't given via proxy_config) doesn't verify the hostname of the certificate. This means certificates for different servers that still validate properly with the default urllib3 SSLContext will be silently accepted.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

urllib3 1.26.x before 1.26.4 fails to verify SSL certificates for HTTPS proxies when no custom SSLContext is provided, allowing man-in-the-middle attacks.

Root

Cause

urllib3 prior to version 1.26.4 omitted SSL certificate hostname verification when establishing connections to HTTPS proxies if a custom SSLContext was not supplied via the proxy_config parameter. The default SSLContext validates certificates against their issuer but does not check that the certificate's subject matches the proxy's hostname. This means any certificate that is otherwise valid (e.g., issued by a trusted CA for a different domain) is silently accepted for the proxy connection [1][2].

Exploitation

The vulnerability can be exploited by an attacker who controls or intercepts traffic to the HTTPS proxy. By presenting a certificate that is valid for a different server (but still passes default validation), the attacker can impersonate the proxy. No additional authentication or network position is required beyond the ability to perform a man-in-the-middle (MITM) attack on the proxy connection [2][3].

Impact

Successful exploitation allows an attacker to intercept, decrypt, and modify traffic between the client and the ultimate HTTPS server. This could lead to exposure of sensitive data, credential theft, or injection of malicious content. The impact is limited to scenarios where HTTPS-to-HTTPS proxy connections are used with urllib3 without custom SSLContext configuration [2].

Mitigation

The issue is fixed in urllib3 version 1.26.4 [3]. Users are strongly advised to upgrade. For those unable to upgrade immediately, a workaround is to provide an explicit SSLContext that performs hostname verification via the proxy_config parameter [1][2]. No active exploitation in the wild has been reported as of the publication date.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
urllib3PyPI
>= 1.26.0, < 1.26.41.26.4

Affected products

2

Patches

1
8d65ea1ecf6e

Merge pull request from GHSA-5phf-pp7p-vc2r

https://github.com/urllib3/urllib3JorgeMar 15, 2021via ghsa
3 files changed · +37 0
  • src/urllib3/connection.py+4 0 modified
    @@ -490,6 +490,10 @@ def _connect_tls_proxy(self, hostname, conn):
                 self.ca_cert_dir,
                 self.ca_cert_data,
             )
    +        # By default urllib3's SSLContext disables `check_hostname` and uses
    +        # a custom check. For proxies we're good with relying on the default
    +        # verification.
    +        ssl_context.check_hostname = True
     
             # If no cert was provided, use only the default options for server
             # certificate validation
    
  • test/conftest.py+11 0 modified
    @@ -64,6 +64,17 @@ def no_san_server(tmp_path_factory):
             yield cfg
     
     
    +@pytest.fixture
    +def no_localhost_san_server(tmp_path_factory):
    +    tmpdir = tmp_path_factory.mktemp("certs")
    +    ca = trustme.CA()
    +    # non localhost common name
    +    server_cert = ca.issue_cert(u"example.com")
    +
    +    with run_server_in_thread("https", "localhost", tmpdir, ca, server_cert) as cfg:
    +        yield cfg
    +
    +
     @pytest.fixture
     def ip_san_server(tmp_path_factory):
         tmpdir = tmp_path_factory.mktemp("certs")
    
  • test/with_dummyserver/test_proxy_poolmanager.py+22 0 modified
    @@ -543,3 +543,25 @@ def test_basic_ipv6_proxy(self):
     
                 r = http.request("GET", "%s/" % self.https_url)
                 assert r.status == 200
    +
    +
    +class TestHTTPSProxyVerification:
    +    @onlyPy3
    +    def test_https_proxy_hostname_verification(self, no_localhost_san_server):
    +        bad_server = no_localhost_san_server
    +        bad_proxy_url = "https://%s:%s" % (bad_server.host, bad_server.port)
    +
    +        # An exception will be raised before we contact the destination domain.
    +        test_url = "testing.com"
    +        with proxy_from_url(bad_proxy_url, ca_certs=bad_server.ca_certs) as https:
    +            with pytest.raises(MaxRetryError) as e:
    +                https.request("GET", "http://%s/" % test_url)
    +            assert isinstance(e.value.reason, SSLError)
    +            assert "hostname 'localhost' doesn't match" in str(e.value.reason)
    +
    +            with pytest.raises(MaxRetryError) as e:
    +                https.request("GET", "https://%s/" % test_url)
    +            assert isinstance(e.value.reason, SSLError)
    +            assert "hostname 'localhost' doesn't match" in str(
    +                e.value.reason
    +            ) or "Hostname mismatch" in str(e.value.reason)
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

19

News mentions

0

No linked articles in our index yet.