-
Couldn't load subscription status.
- Fork 3.2k
Description
InsecureCacheControlAdapter raises ValueError with certain SSL contexts
Summary
InsecureCacheControlAdapter (and InsecureHTTPAdapter) override cert_verify() to force verify=False but don't override get_connection_with_tls_context(). This creates a state where ssl_context.check_hostname=True and cert_reqs=CERT_NONE are set simultaneously, causing a ValueError during SSL connection setup.
Note: I do not believe this currently affects any "normal" pip usage, so I don't neccesarily expect it to be fixed here, I just thought it was worth raising in case you / the maintainers are interested and think it might affect pip directly.
Environment
- Python: 3.10, 3.11, 3.12
- pip: 24.2+
- Triggered when using
trusted-hostconfiguration with certain SSL context modifications
Bug Report
Observed Behavior
When using pip install with a trusted-host configuration after certain global SSL modifications (e.g., packages that call truststore.inject_into_ssl()), pip fails with:
ValueError: Cannot set verify_mode to CERT_NONE when check_hostname is enabled.
Root Cause
The InsecureCacheControlAdapter and InsecureHTTPAdapter classes in pip/_internal/network/session.py only override cert_verify():
class InsecureCacheControlAdapter(CacheControlAdapter):
def cert_verify(self, conn, url, verify, cert):
super().cert_verify(conn=conn, url=url, verify=False, cert=cert)The execution flow in HTTPAdapter.send():
- Calls
get_connection_with_tls_context(request, verify, ...)with originalverifyvalue - This creates an SSL context potentially with
check_hostname=True - Then calls
cert_verify(conn, ..., verify, ...)which forcesverify=False - urllib3's connection code attempts:
context.verify_mode = CERT_NONE - Python's ssl module raises
ValueErrorifcheck_hostname=True
Reproduction
This bug is exposed by the pip-system-certs package which calls truststore.inject_into_ssl(), but the underlying issue exists in pip's adapter implementation.
Minimal reproduction:
- Create
pip.ini:
[global]
trusted-host = pypi.org-
Install a package that modifies SSL globally (e.g.,
pip-system-certs) -
Set environment:
export PIP_CONFIG_FILE=/path/to/pip.ini -
Run:
pip install anyio -
Observe:
ValueError: Cannot set verify_mode to CERT_NONE when check_hostname is enabled.
Impact
- Affects users combining
trusted-hostconfiguration with packages that modify global SSL behavior - Breaks pip functionality in corporate/institutional environments using custom CA certificates and trusted hosts
- Currently affecting pip-system-certs users (see https://gitlab.com/alelec/pip-system-certs/-/issues/39)
Proposed Fix
Override get_connection_with_tls_context() to force verify=False consistently:
class InsecureCacheControlAdapter(CacheControlAdapter):
def cert_verify(self, conn, url, verify, cert):
super().cert_verify(conn=conn, url=url, verify=False, cert=cert)
def get_connection_with_tls_context(self, request, verify, proxies=None, cert=None):
# Force verify=False to prevent check_hostname conflict
return super().get_connection_with_tls_context(
request, verify=False, proxies=proxies, cert=cert
)The same fix should be applied to InsecureHTTPAdapter.
Credit
Analysis and proposed fix by @kjmrr: https://gitlab.com/alelec/pip-system-certs/-/issues/39#note_2812939884
Workaround
pip-system-certs has implemented a defensive runtime patch as a temporary workaround. The proper fix belongs upstream in pip.
Additional context:
This is a latent bug that requires specific conditions to trigger:
- Global SSL context modification (e.g., via truststore)
- Usage of
trusted-hostconfiguration - The modified SSL contexts having
check_hostname=True
While exposed by pip-system-certs, the bug exists in pip's implementation and could affect other scenarios where SSL contexts are modified globally.