Safeguard
Vulnerability Analysis

Python requests library proxy-auth credential leak (CVE-2023-32681)

CVE-2023-32681 lets Python's requests library leak Proxy-Authorization credentials to destination servers on HTTPS redirects. Here's the impact, timeline, and fix.

Yukti Singhal
Security Analyst
8 min read

In May 2023, the maintainers of the Python requests library — arguably the most widely used HTTP client in the Python ecosystem, pulled in by hundreds of thousands of projects — patched a vulnerability that had been sitting in the codebase for nearly a decade. Tracked as CVE-2023-32681, the flaw causes requests to leak the Proxy-Authorization header to destination servers when a request routed through an HTTPS proxy is redirected to an HTTPS origin. In plain terms: credentials meant only for your proxy can end up in the hands of whatever server the proxy forwards you to, including a server controlled by an attacker.

Because requests sits at the base of the dependency tree for an enormous share of the Python ecosystem — pip itself vendors it, and it's a transitive dependency of countless SDKs, data pipelines, and internal tooling — this is exactly the kind of vulnerability that security teams need to triage quickly and accurately, rather than reflexively patching every service that happens to import requests regardless of whether it actually uses proxy authentication.

What the vulnerability actually does

requests supports routing traffic through HTTP or HTTPS proxies, with optional Basic Auth credentials supplied via the proxy URL (e.g., https://user:pass@proxy.internal:8080) or set directly on a Proxy-Authorization header. When a request is sent to an HTTPS origin through a proxy, the client establishes a tunnel using an HTTP CONNECT request, and the Proxy-Authorization header is legitimately included in that CONNECT request so the proxy can authenticate the client.

The bug lives in how requests handles redirects. Internally, the library calls a method named rebuild_proxies to reattach proxy configuration — including the Proxy-Authorization header — whenever a redirect is followed. For plain HTTP destinations, this isn't a problem: the proxy sits in the middle of every request and strips the header before forwarding traffic onward, because it can see the request contents. But for HTTPS destinations, the proxy only sees the initial CONNECT tunnel setup; after that, traffic is encrypted end-to-end between the client and the origin server. requests was reattaching the Proxy-Authorization header to the tunneled request itself, meaning that header traveled all the way to the destination server rather than terminating at the proxy.

The practical exploitation path is straightforward: a redirect (3xx response) from a proxied HTTPS request to another HTTPS origin will cause the client to unintentionally hand its proxy credentials to whatever host is at the other end of that redirect. That host could be a legitimate but compromised service, a malicious actor who controls a redirect target in a chain (e.g., via an open redirect on an intermediate service), or simply a logging/analytics endpoint that will now have a Base64-encoded proxy password sitting in its access logs.

Affected versions and components

  • Vulnerable: requests versions 2.3.0 through 2.30.0 (the rebuild_proxies behavior was introduced in 2.3.0, released in 2014).
  • Fixed in: requests 2.31.0, released May 26, 2023.
  • Advisory: GHSA-9wx4-h78v-vm56, published by the Python Software Foundation / psf security team.
  • Root cause component: requests.sessions.Session.rebuild_proxies().

The prerequisite for exploitation is that the affected application must be configured to use an authenticated HTTPS proxy (i.e., proxy credentials embedded in the connection configuration), and must follow redirects (the default allow_redirects=True behavior) to an HTTPS destination. Environments that don't use proxy authentication, or that pin allow_redirects=False and handle redirects manually with fresh sessions, are not exposed by this specific path. This nuance matters a great deal for triage — it is the difference between "every service using requests is at risk" and "the subset of services that route through an authenticated corporate or third-party proxy are at risk."

Because requests is bundled or vendored by other widely-deployed tools (notably pip, various cloud SDKs, and CI/CD utilities), organizations should expect this CVE to surface not just as a direct dependency but nested several layers deep in SBOMs and lockfiles.

CVSS, EPSS, and KEV context

NVD scored CVE-2023-32681 at CVSS 3.1 base score 6.1 (Medium), with a vector reflecting network attack vector, high attack complexity (the attacker needs a redirect chain and a proxy-authenticated victim), no privileges required, no user interaction, and high confidentiality impact with no integrity or availability impact. The "high attack complexity" rating is doing a lot of work here — it reflects the fact that exploitation depends on a specific proxy + redirect configuration rather than being a trivially remote, unauthenticated attack against any requests user.

EPSS (Exploit Prediction Scoring System) has historically placed this CVE in the lower percentile bands typical of credential-disclosure bugs that require a specific network topology to exploit, rather than a wormable or drive-by pattern. As of this writing, CVE-2023-32681 does not appear on CISA's Known Exploited Vulnerabilities (KEV) catalog, indicating no confirmed evidence of in-the-wild exploitation has been publicly attributed to it. That said, absence from KEV is not a reason for deprioritization on its own — credential-leak bugs of this shape are attractive for passive collection (an attacker doesn't need to actively exploit anything if they simply control or compromise a redirect target and wait for credentials to arrive in their logs), which is a pattern that tends to under-report to threat intelligence feeds.

Timeline

  • 2014: requests 2.3.0 introduces the rebuild_proxies redirect-handling logic that would later become the root cause.
  • Prior to May 2023: The behavior persists undetected through multiple major and minor requests releases across nearly a decade of widespread adoption.
  • May 2023: The issue is reported to the psf/requests maintainers via a GitHub security advisory.
  • May 26, 2023: requests 2.31.0 is released, removing the automatic reattachment of Proxy-Authorization on cross-origin HTTPS redirects.
  • June 2023: CVE-2023-32681 and GHSA-9wx4-h78v-vm56 are published, formally documenting the vulnerability and assigning severity.
  • Following weeks/months: Downstream projects that pin or vendor requests (Python distributions, cloud SDKs, security scanners, CI images) begin bumping minimum supported versions to 2.31.0 in their own release notes.

Remediation steps

  1. Upgrade requests to 2.31.0 or later across all applications, services, base images, and CI/CD pipelines. This is the definitive fix — the redirect logic no longer blindly reattaches Proxy-Authorization to cross-origin destinations.
  2. Audit transitive dependencies, not just direct requirements.txt/pyproject.toml entries. Check whether internal tooling, vendored copies, or third-party SDKs bundle an older requests version. pip list, pip show requests, and dependency-tree tools (pipdeptree, poetry show --tree) can surface this quickly; an SBOM is faster still if one already exists.
  3. Rotate proxy credentials for any environment that (a) ran a vulnerable requests version, (b) uses authenticated HTTPS proxies, and (c) has processed redirect chains to external or untrusted HTTPS hosts during the exposure window. Treat any credentials that could plausibly have been sent to a third party as compromised.
  4. Review egress and proxy logs for evidence of Proxy-Authorization headers appearing in destination-server request logs, or unexpected outbound requests to unfamiliar hosts following a redirect from a proxied session.
  5. Constrain redirect behavior where proxy auth is in use. Where upgrading isn't immediately possible, consider setting allow_redirects=False and handling redirects explicitly with a freshly-scoped session/proxy configuration, or restrict proxy credential use to same-origin destinations only.
  6. Prefer non-Basic-Auth proxy authentication schemes (e.g., mutual TLS to the proxy, network-level allowlisting) where feasible, since header-based credentials are the specific mechanism this class of bug exposes.
  7. Pin a minimum version going forward (requests>=2.31.0) in dependency manifests and enforce it via CI checks so a future downgrade or an unpinned transitive resolution doesn't silently reintroduce the vulnerable code path.

How Safeguard Helps

Blanket "you're using requests, patch immediately" alerts create fatigue and obscure the services that are actually exploitable. Safeguard's reachability analysis determines whether an application's call graph actually exercises the vulnerable rebuild_proxies redirect path with proxy authentication configured, so your team can prioritize the handful of internet-facing, proxy-authenticated services over the hundreds of unaffected internal scripts that also happen to import requests. Our Griffin AI engine correlates that reachability signal with CVSS, EPSS, and exposure context to rank CVE-2023-32681 findings by real-world risk rather than raw severity score alone. Safeguard's SBOM generation and ingestion capabilities surface every vendored or transitive copy of requests across your fleet — including the ones buried three dependencies deep inside a CI tool or cloud SDK — so nothing gets missed during triage. And where a fix is warranted, Safeguard can open an auto-fix pull request that bumps requests to a patched release and pins the minimum version, turning a manual dependency hunt into a reviewable, one-click merge.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.