CVE-2026-15806 Overview
CVE-2026-15806 is a cleartext transmission vulnerability [CWE-319] in the Python urllib.request module. The HTTPPasswordMgr class and its subclasses HTTPPasswordMgrWithDefaultRealm and HTTPPasswordMgrWithPriorAuth did not consider the URL scheme when matching stored credentials to a requested URL. Credentials registered for an https:// URL were reused when the client made requests to the same host over http://. An attacker positioned to redirect or downgrade traffic to plain HTTP can capture credentials in cleartext. The reverse case also applies, allowing http:// credentials to leak over https:// requests.
Critical Impact
Attackers with an on-path position or the ability to force an HTTPS-to-HTTP redirect can harvest authentication credentials transmitted in cleartext by Python client applications using urllib.request.
Affected Products
- Python CPython 3.12 branch (prior to patched release)
- Python CPython 3.14 branch (prior to patched release)
- Python CPython 3.15 branch (prior to patched release)
Discovery Timeline
- 2026-08-18 - CVE-2026-15806 published to NVD
- 2026-08-21 - Last updated in NVD database
Technical Details for CVE-2026-15806
Vulnerability Analysis
The defect resides in credential matching logic within Lib/urllib/request.py. The HTTPPasswordMgr.add_password() method stored authentication tuples keyed by a reduced URI that discarded the scheme component. When find_user_password() was later invoked to look up credentials for an outgoing request, it applied the same scheme-stripping reduction, producing a match regardless of whether the request used http:// or https://. Applications registering credentials against an https:// endpoint therefore emitted the same Authorization header over plaintext HTTP when redirects or client logic caused a scheme downgrade.
The weakness maps to CWE-319: Cleartext Transmission of Sensitive Information because it enables credentials intended for encrypted transport to traverse unencrypted channels.
Root Cause
The root cause is the reduce_uri() helper stripping the URL scheme before comparison. Credential storage and lookup both operated on a scheme-agnostic key, breaking the security boundary between HTTP and HTTPS origins. The fix introduces _reduce_uri_with_scheme() and _is_suburi_with_scheme() to preserve scheme context during matching.
Attack Vector
Exploitation requires an attacker who can either operate as an on-path adversary or induce the client to follow a redirect from https:// to http://. When the vulnerable client issues the downgraded request, urllib.request attaches the previously registered credentials, and the attacker captures the Authorization header from the plaintext stream.
# Security patch in Lib/urllib/request.py
# Source: https://github.com/python/cpython/commit/641be42bb07921ba0f8bffe228b1dc706b092ef6
self.passwd[realm] = {}
for default_port in True, False:
reduced_uri = tuple(
- self.reduce_uri(u, default_port) for u in uri)
+ self._reduce_uri_with_scheme(u, default_port) for u in uri)
self.passwd[realm][reduced_uri] = (user, passwd)
def find_user_password(self, realm, authuri):
domains = self.passwd.get(realm, {})
for default_port in True, False:
- reduced_authuri = self.reduce_uri(authuri, default_port)
+ reduced_authuri = self._reduce_uri_with_scheme(
+ authuri, default_port)
for uris, authinfo in domains.items():
for uri in uris:
- if self.is_suburi(uri, reduced_authuri):
+ if self._is_suburi_with_scheme(uri, reduced_authuri):
return authinfo
return None, None
This patch replaces the scheme-agnostic reduction functions with scheme-aware equivalents. Credentials registered with a URI that includes a scheme now only match authentication URIs of the same scheme. Bare-authority entries such as example.com:8080 continue to match any scheme, preserving proxy authentication behavior.
Detection Methods for CVE-2026-15806
Indicators of Compromise
- Outbound HTTP requests carrying an Authorization: Basic header to hosts that also serve HTTPS.
- HTTP 301 or 302 responses that redirect from https:// to http:// for internal service endpoints.
- Unexpected plaintext authentication attempts on ports 80 or 8080 originating from Python-based automation, scrapers, or CI/CD workers.
Detection Strategies
- Inspect network telemetry for Authorization headers appearing on cleartext HTTP flows sourced from application servers running Python.
- Audit application source code for use of HTTPPasswordMgr, HTTPPasswordMgrWithDefaultRealm, and HTTPPasswordMgrWithPriorAuth combined with URIs that omit http:// or https:// schemes.
- Enumerate installed Python interpreters across endpoints and compare their versions against the patched CPython 3.12, 3.14, and 3.15 releases referenced in the Python Security Announcement.
Monitoring Recommendations
- Alert on HTTP 3xx responses that downgrade a session from HTTPS to HTTP toward hosts holding authenticated APIs.
- Log and review outbound proxy traffic for Basic or Digest authentication traversing unencrypted channels.
- Track Python runtime inventories through package management telemetry to identify hosts still running vulnerable interpreters.
How to Mitigate CVE-2026-15806
Immediate Actions Required
- Upgrade CPython to the patched releases on the 3.12, 3.14, and 3.15 branches referenced in the Python Security Announcement.
- Rotate any credentials that were registered through HTTPPasswordMgr and may have traversed unencrypted HTTP.
- Audit dependencies and internal tools that use urllib.request with authenticated URLs for redirect-following behavior.
Patch Information
The fix scopes credential matching by URL scheme via the introduction of _reduce_uri_with_scheme() and _is_suburi_with_scheme() in Lib/urllib/request.py. The change ships in the corresponding maintenance releases of Python 3.12, 3.14, and 3.15 through commits 641be42, 851cf9a, and a0d023f. Additional context is available in GitHub Issue #155694 and GitHub Pull Request #155696.
Workarounds
- Prevent client code from following redirects that change the scheme from https:// to http:// by subclassing HTTPRedirectHandler and rejecting such transitions.
- Register credentials only against fully qualified https:// URIs and validate at runtime that outbound requests remain on HTTPS before dispatch.
- Enforce egress policies that block plaintext HTTP to hosts known to serve authenticated APIs, forcing clients onto TLS.
# Configuration example: verify the running Python version is patched
python3 -c "import sys; print(sys.version)"
# Upgrade example using pip-managed environments
python3 -m pip install --upgrade --index-url https://pypi.org/simple 'python>=3.12'
# Verify no unpatched interpreters remain on the host
find / -type f -name 'python3*' -executable 2>/dev/null -exec {} --version \;
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

