Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-15806

CVE-2026-15806: urllib.request Information Disclosure Flaw

CVE-2026-15806 is an information disclosure vulnerability in Python's urllib.request module that allows credentials to leak across HTTP/HTTPS schemes. This article covers the technical details, affected versions, and mitigation steps.

Published:

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.

python
# 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.
bash
# 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.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.