See how python compares to other vendors in security performance
When decompressing crafted zip files using the bzip/LZMA/Zstandard
compressions, Python could use an attacker-controlled size to
pre-allocate memory, possibly resulting in memory exhaustion.
Impact
urllib3's streaming API is designed for the efficient handling of large HTTP responses by reading the content in chunks, rather than loading the entire response body into memory at once.
urllib3 can perform decoding or decompression based on the HTTP Content-Encoding header (e.g., gzip, deflate, br, or zstd). When using the streaming API, the library decompresses only the necessary bytes, enabling partial content consumption.
However, for HTTP redirect responses, the library would read the entire response body to drain the connection and decompress the content unnecessarily. This decompression occurred even before any read methods were called, and configured read limits did not restrict the amount of decompressed data. As a result, there was no safeguard against decompression bombs. A malicious server could exploit this to trigger excessive resource consumption on the client (high CPU usage and large memory allocations for decompressed data; CWE-409).
Affected usages
Applications and libraries using urllib3 version 2.6.2 and earlier to stream content from untrusted sources by setting preloadcontent=False when they do not disable redirects.
Remediation
Upgrade to at least urllib3 v2.6.3 in which the library does not decode content of redirect responses when preloadcontent=False.
If upgrading is not immediately possible, disable redirects by setting redirect=False for requests to untrusted source.
Out-of-memory when loading Plist
Excessive read buffering DoS in http.client
The "stringprep" module didn't process characters from RFC 3454 tables B.2 or B.3 correctly: the latest Unicode codepoint attributes were used instead of the specified Unicode 3.2.0. This behavior would cause mismatches when processing domain names using IDNA 2003 (the "idna" codec) and the intableb2() function of the "stringprep" module. This only affects domain names containing characters that were not previously registered or had their Unicode attributes such as case-folding behavior updated since Unicode 3.2.0.
The HTTPPasswordMgr class in the urllib.request module, along with its subclasses HTTPPasswordMgrWithDefaultRealm and HTTPPasswordMgrWithPriorAuth, did not take the URL scheme into account when matching stored credentials against a requested URL. Credentials added for an https:// URL were also used for requests to the same host over http://, so an attacker able to redirect or downgrade a client to plain HTTP (for example, via an HTTPS-to-HTTP redirect or an on-path position) could capture credentials in cleartext. Credentials added for http:// URLs could likewise be sent over https://.
Credential matching is now scoped by URL scheme. Credentials registered with a URL that includes a scheme are only used for requests with the same scheme. Credentials registered with a bare authority (such as example.com or example.com:8080) continue to match any scheme, preserving compatibility with existing code, including proxy authentication.
Users who cannot upgrade immediately can mitigate by ensuring that applications never make plain http:// requests to hosts for which credentials are registered, for example by not following redirects to http:// URLs.
Impact Pillow did not limit the amount of GZIP-compressed data read when decoding a FITS image, making it vulnerable to decompression bomb attacks. A specially crafted FITS file could cause unbounded memory consumption, leading to denial of service (OOM crash or severe performance degradation).
Patches The amount of data read is now limited to the necessary amount. Fixed in Pillow 12.2.0 (PR #9521).
Workarounds Avoid Pillow >= 10.3.0, < 12.2.0 Only open specific image formats, excluding FITS.
AIONLYREPORT package: python-pip-26.0.1-2.1.hum1 ------ Summary: Path Traversal via Malicious Entry Point Name in Wheel Metadata: A malicious wheel can use traversal or absolute entry-point names so pip writes generated script wrappers outside the intended scheme.scripts directory and overwrites files writable by the installing user. Requirements to exploit: An attacker must induce a victim to install a malicious wheel. The wheel must contain crafted consolescripts or guiscripts names with ../ traversal or absolute-path components in entrypoints.txt. The resulting overwrite is limited by the permissions of the installing user, but pip’s wheel-install flow reaches the vulnerable write path in normal operation and sets maker.clobber = True, so existing writable files are replaced when reachable. Component affected: github.com/pypa/pip - wheel installation flow in src/pip/internal/operations/install/wheel.py, vendored distlib script generation in src/pip/vendor/distlib/scripts.py, and entry-point parsing in src/pip/vendor/distlib/util.py Version affected: 26.0.1 (confirmed). Likely affects versions containing the same getentrypoints(...) -> getconsolescriptspecs(...) -> ScriptMaker.writescript(...) flow without target-directory enforcement. Patch available: no (a minimal proposed fix is included below; upstream release status unknown) Version fixed (if any already): unknown Upstream coordination: Not yet notified. This report is the initial triage. CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H AV:N - An attacker can distribute a malicious wheel through a package source or other network-delivered artifact. AC:L - Crafting traversal or absolute entry-point names in entrypoints.txt is straightforward. PR:N - The attacker needs no privileges on the victim system. UI:R - The victim must install the malicious wheel. S:U - Impact remains within the installing user's security scope. C:N - The primitive is attacker-controlled file overwrite, not direct data disclosure by default. I:H - Escaping scheme.scripts can overwrite writable files outside the intended install directory. A:H - Overwriting critical writable files can break applications or system behavior. Impact: Likely Important. This is a real arbitrary file overwrite/path traversal flaw in pip’s wheel installation flow. Exploitation requires a victim to install a malicious wheel, and the overwrite is limited to paths writable by the installing user. The written content is constrained to pip’s generated entry-point wrapper format rather than fully arbitrary bytes, which narrows the direct confidentiality impact, but escaping scheme.scripts can still severely affect integrity and availability and can lead to code execution when privileged or security-sensitive targets are overwritten. Embargo: yes Reason: No official fix is available, and the bug turns a malicious wheel into a write primitive outside the intended installation directory during a normal pip install flow. Public disclosure before a fix would make malicious package distribution campaigns easier, especially where wheels are installed with elevated privileges. Suggested public date: 15-Jul-2026 Acknowledgement: Aisle Research Steps to reproduce: 1. From the unpacked source tree, run: bash python - <<'PY' import os, tempfile, sys sys.path.insert(0, 'src') from pip.internal.operations.install.wheel import PipScriptMaker base = tempfile.mkdtemp(prefix='pip-script-test-') scripts = os.path.join(base, 'bin') os.makedirs(scripts, existok=True) absolutetarget = os.path.join(tempfile.gettempdir(), 'pip-owned') maker = PipScriptMaker(None, scripts) maker.clobber = True maker.variants = {''} maker.setmode = False for spec in [f'../../outside = os:path.join', f'{absolutetarget} = os:path.join']: files = maker.make(spec) print(spec, '->', files[0], '=>', os.path.abspath(files[0])) PY 2. Observe that the generated output path resolves outside scripts and that the file is written. 3. In a real installation context, a malicious wheel that places the same crafted names in entrypoints.txt reaches the same write sink during pip install and can overwrite attacker-chosen files writable by the installing user. Mitigation: Do not install untrusted wheels, especially in privileged contexts.
Avoid sudo pip install or other elevated wheel-install workflows until a fix is available.
Reject or inspect wheels whose entrypoints.txt contains path separators, .., or absolute entry-point names.
Vulnerability Details
pip already enforces path-traversal checks for wheel archive members extracted from the .whl, but generated entry-point wrappers are created later from metadata and do not go through that containment check. The vulnerable flow is: getentrypoints(distribution) reads consolescripts and guiscripts names from wheel metadata.
getconsolescriptspecs() formats those names into script specifications without sanitizing the name component.
PipScriptMaker.makemultiple() forwards the names to vendored distlib.
ScriptMaker.writescript() uses os.path.join(self.targetdir, name) and writes the generated wrapper without verifying that the resolved path stays inside targetdir.
Additional stage-5 verification confirmed that this is not limited to a direct PipScriptMaker API call: the full wheel-metadata path is reachable in both supported metadata backends, and absolute entry-point names are accepted in addition to ../ traversal. Relevant CWEs: CWE-22 (Path Traversal)
CWE-73 (External Control of File Name or Path)
Proposed Fix
A minimal defense-in-depth fix is to enforce that each generated script path remains inside targetdir before writing: diff diff --git a/src/pip/vendor/distlib/scripts.py b/src/pip/vendor/distlib/scripts.py @@ for name in names: outname = os.path.join(self.targetdir, name) + targetdir = os.path.abspath(self.targetdir) + outnameabs = os.path.abspath(outname) + if os.path.commonpath([targetdir, outnameabs]) != targetdir: + raise ValueError("Invalid script name %r: path traversal/absolute path" % name) if uselauncher: # pragma: no cover n, e = os.path.splitext(outname) Optionally, reject path separators and absolute paths earlier when parsing or validating entry-point names. ------ This report was generated using AI technology. Always review AI-generated content prior to use
Summary A path traversal vulnerability in PackageIndex was fixed in setuptools version 78.1.1
Details def downloadurl(self, url, tmpdir): # Determine download filename # name, fragment = egginfoforurl(url) if name: while '..' in name: name = name.replace('..', '.').replace('\\', '') else: name = "downloaded" # default if URL has no path contents
if name.endswith('.egg.zip'): name = name[:-4] # strip the extra .zip before download
--> filename = os.path.join(tmpdir, name)
Here: https://github.com/pypa/setuptools/blob/6ead555c5fb29bc57fe6105b1bffc163f56fd558/setuptools/packageindex.py#L810C1-L825C88
os.path.join() discards the first argument tmpdir if the second begins with a slash or drive letter. name is derived from a URL without sufficient sanitization. While there is some attempt to sanitize by replacing instances of '..' with '.', it is insufficient.
Risk Assessment As easyinstall and packageindex are deprecated, the exploitation surface is reduced. However, it seems this could be exploited in a similar fashion like https://github.com/advisories/GHSA-r9hx-vwmv-q579, and as described by POC 4 in https://github.com/advisories/GHSA-cx63-2mw6-8hw5 report: via malicious URLs present on the pages of a package index.
Impact An attacker would be allowed to write files to arbitrary locations on the filesystem with the permissions of the process running the Python code, which could escalate to RCE depending on the context.
References https://huntr.com/bounties/d6362117-ad57-4e83-951f-b8141c6e7ca5 https://github.com/pypa/setuptools/issues/4946
Impact
urllib3's streaming API is designed for the efficient handling of large HTTP responses by reading the content in chunks, rather than loading the entire response body into memory at once.
When streaming a compressed response, urllib3 can perform decoding or decompression based on the HTTP Content-Encoding header (e.g., gzip, deflate, br, or zstd). The library must read compressed data from the network and decompress it until the requested chunk size is met. Any resulting decompressed data that exceeds the requested amount is held in an internal buffer for the next read operation.
The decompression logic could cause urllib3 to fully decode a small amount of highly compressed data in a single operation. This can result in excessive resource consumption (high CPU usage and massive memory allocation for the decompressed data; CWE-409) on the client side, even if the application only requested a small chunk of data.
Affected usages
Applications and libraries using urllib3 version 2.5.0 and earlier to stream large compressed responses or content from untrusted sources.
stream(), read(amt=256), read1(amt=256), readchunked(amt=256), readinto(b) are examples of urllib3.HTTPResponse method calls using the affected logic unless decoding is disabled explicitly.
Remediation
Upgrade to at least urllib3 v2.6.0 in which the library avoids decompressing data that exceeds the requested amount.
If your environment contains a package facilitating the Brotli encoding, upgrade to at least Brotli 1.2.0 or brotlicffi 1.2.0.0 too. These versions are enforced by the urllib3[brotli] extra in the patched versions of urllib3.
Credits
The issue was reported by @Cycloctane. Supplemental information was provided by @stamparm during a security audit performed by 7ASecurity and facilitated by OSTIF.
Impact
urllib3 supports chained HTTP encoding algorithms for response content according to RFC 9110 (e.g., Content-Encoding: gzip, zstd).
However, the number of links in the decompression chain was unbounded allowing a malicious server to insert a virtually unlimited number of compression steps leading to high CPU usage and massive memory allocation for the decompressed data.
Affected usages
Applications and libraries using urllib3 version 2.5.0 and earlier for HTTP requests to untrusted sources unless they disable content decoding explicitly.
Remediation
Upgrade to at least urllib3 v2.6.0 in which the library limits the number of links to 5.
If upgrading is not immediately possible, use preloadcontent=False and ensure that resp.headers["content-encoding"] contains a safe number of encodings before reading the response content.
An issue was found in the CPython tempfile.TemporaryDirectory class affecting versions 3.12.1, 3.11.7, 3.10.13, 3.9.18, and 3.8.18 and prior.
The tempfile.TemporaryDirectory class would dereference symlinks during cleanup of permissions-related errors. This means users which can run privileged programs are potentially able to modify permissions of files referenced by symlinks in some circumstances.
https://github.com/python/cpython/commit/02a9259c717738dfe6b463c44d7e17f2b6d2cb3a https://github.com/python/cpython/commit/5585334d772b253a01a6730e8202ffb1607c3d25 https://github.com/python/cpython/commit/6ceb8aeda504b079fef7a57b8d81472f15cdd9a5 https://github.com/python/cpython/commit/81c16cd94ec38d61aa478b9a452436dc3b1b524d https://github.com/python/cpython/commit/8eaeefe49d179ca4908d052745e3bb8b6f238f82 https://github.com/python/cpython/commit/d54e22a669ae6e987199bb5d2c69bb5a46b0083b https://github.com/python/cpython/issues/91133 https://lists.debian.org/debian-lts-announce/2024/03/msg00025.html https://mail.python.org/archives/list/security-announce@python.org/thread/Q5C6ATFC67K53XFV4KE45325S7NS62LD/
The tarfile module's tar and data extraction filters created directories outside the destination for members whose name leaves the destination and returns to it, such as ../evil/../dest/sub/file. The containment check used the resolved path, but intermediate directories were created from the name as given.
Only empty directories are created outside the destination. Member contents are still extracted inside it. To return to the destination the member's name must contain the destination directory's own final component, so extraction into a secure randomised directory is not affected.
This affects POSIX platforms only. On Windows, .. components are collapsed before the path reaches the filesystem, so the directories outside the destination are never created.
Impact
urllib3's streaming API is designed for the efficient handling of large HTTP responses by reading the content in chunks, rather than loading the entire response body into memory at once.
urllib3 can perform decompression based on the HTTP Content-Encoding header (e.g., gzip, deflate, br, or zstd). When using the streaming API since version 2.6.0, the library decompresses only the necessary bytes, enabling partial content consumption.
However, urllib3 before version 2.7.0 could still decompress the whole response instead of the requested portion in two cases: 1. During the second HTTPResponse.read(amt=N) call when the response was decompressed using the official Brotli library. 2. When HTTPResponse.drainconn() was called after the response had been read and decompressed partially (compression algorithm did not matter here).
These issues could cause urllib3 to fully decode a small amount of highly compressed data in a single operation. This could result in excessive resource consumption (high CPU usage and massive memory allocation for the decompressed data; CWE-409) on the client side.
Affected usages
Applications and libraries using urllib3 versions earlier than 2.7.0 may be affected when streaming compressed responses from untrusted sources in either of these cases, unless decompression is explicitly disabled:
1. A response encoded with br is read incrementally with at least two HTTPResponse.read(amt=N) or HTTPResponse.stream(amt=N) calls while using the official Brotli library. 2. HTTPResponse.drainconn() is called after response decompression has already started.
Remediation
Upgrade to at least urllib3 version 2.7.0 in which the library: 1. Is more efficient for reads with Brotli. 2. Always skips decompression for HTTPResponse.drainconn().
If upgrading is not immediately possible, the following workarounds may reduce exposure in specific cases: 1. For the Brotli-specific issue only, switch from brotli to brotlicffi until you can upgrade urllib3; the official Brotli package is affected because of https://github.com/google/brotli/issues/1396. 2. If your code explicitly calls HTTPResponse.drainconn(), call HTTPResponse.close() instead when connection reuse is not important.
Credits
The Brotli-specific issue was reported by @kimkou2024. HTTPResponse.drainconn() inefficiency was reported by @Cycloctane.
Impact
Black provides a GitHub action for formatting code. This action supports an option, usepyproject: true, for reading the version of Black to use from the repository pyproject.toml. A malicious pull request could edit pyproject.toml to use a direct URL reference to a malicious repository. This could lead to arbitrary code execution in the context of the GitHub Action. Attackers could then gain access to secrets or permissions available in the context of the action.
Patches
Version 26.3.0 fixes this vulnerability by tightening the validation of the version field. Users who use the GitHub Action as psf/black@stable will automatically pick up this update.
Workarounds
Do not use the usepyproject: true option in the psf/black GitHub Action.
Impact
Black writes a cache file, the name of which is computed from various formatting options. The value of the --python-cell-magics option was placed in the filename without sanitization, which allowed an attacker who controls the value of this argument to write cache files to arbitrary file system locations.
Patches
Fixed in Black 26.3.1.
Workarounds
Do not allow untrusted user input into the value of the --python-cell-magics option.
Impact
When following cross-origin redirects for requests made using urllib3’s high-level APIs, such as urllib3.request(), PoolManager.request(), and ProxyManager.request(), sensitive headers — Authorization, Cookie, and Proxy-Authorization (defined in Retry.DEFAULTREMOVEHEADERSONREDIRECT) — are stripped by default, as expected.
However, cross-origin redirects followed from the low-level API via ProxyManager.connectionfromurl().urlopen(..., assertsamehost=False) still forward these sensitive headers.
Affected usage
Applications and libraries using urllib3 versions earlier than 2.7.0 may be affected if they allow cross-origin redirects while making requests through HTTPConnection.urlopen() instances created via ProxyManager.connectionfromurl().
Remediation
Upgrade to urllib3 version 2.7.0 or later, in which sensitive headers are stripped from redirects followed by HTTPConnection.
If upgrading is not immediately possible, avoid using this low-level redirect flow for cross-origin redirects. If appropriate for your use case, switch to ProxyManager.request().
-------- Forwarded Message -------- Subject: [Security-announce][CVE-2026-19672] tarfile extraction filter bypass allows creation of directories outside the destination Date: Wed, 19 Aug 2026 14:56:06 +0100 From: Stan Ulbrych via Security-announce <security-announce () python org> Reply-To: security-sig () python org To: security-announce () python org CC: Stan Ulbrych <stanulbrych () gmail com>
There is a MEDIUM severity vulnerability affecting CPython.
The tarfile module's tar and data extraction filters created directories outside the destination for members whose name leaves the destination and returns to it, such as ../evil/../dest/sub/file. The containment check used the resolved path, but intermediate directories were created from the name as given.
Only empty directories are created outside the destination. Member contents are still extracted inside it. To return to the destination the member's name must contain the destination directory's own final component, so extraction into a secure randomised directory is not affected.
This affects POSIX platforms only. On Windows, .. components are collapsed before the path reaches the filesystem, so the directories outside the destination are never created.
Please see the linked CVE ID for the latest information on affected versions:
https://www.cve.org/CVERecord?id=CVE-2026-19672 https://github.com/python/cpython/pull/156000
Security-announce mailing list -- security-announce () python org https://mail.python.org/mailman3//lists/security-announce.python.org
tarfile.extractall() with the 'data' or 'tar' filter could be bypassed by a crafted archive where a hardlink references a symlink stored at a deeper name than the hardlink itself. The extraction fallback validated the symlink at it's archived location but recreated it at the hardlink's shallower path, letting a relative target the filter judged contained escape the destination directory. This allowed a malicious tar archive to create a symlink pointing outside the destination, enabling out-of-destination file reads or writes. This was an incomplete fix of CVE-2025-4330.
tarfile.extractall() with the 'data' or 'tar' filter could be bypassed by a crafted archive where a hardlink references a symlink stored at a deeper name than the hardlink itself. The extraction fallback validated the symlink at it's archived location but recreated it at the hardlink's shallower path, letting a relative target the filter judged contained escape the destination directory. This allowed a malicious tar archive to create a symlink pointing outside the destination, enabling out-of-destination file reads or writes. This was an incomplete fix of CVE-2025-4330.
Attacker-controlled CSV samples can trigger super-linear regular-expression work during dialect sniffing and consume significant CPU when applications pass unbounded input to csv.Sniffer.sniff().
Last updated 6 July 2026
Internationalized Domain Names in Applications (IDNA) for Python provides support for Internationalized Domain Names in Applications (IDNA) and Unicode IDNA Compatibility Processing. In versions prior to 3.15, payloads such as "\u0660" N or "\u30fb" N + "\u6f22" utilize the validcontexto function prior to length rejection, and for high values of N will take a long time to process. This is the same issue as CVE-2024-3651, however the original remediation in 2024 was not a complete fix. A specially crafted argument to the idna.encode() function could consume significant resources. This may lead to a denial-of-service. Starting in version 3.14, the function rejects long inputs as soon as practicable prior to any further processing to minimize resource consumption. In version 3.15, this approach was extended to lesser used alternate functions (i.e. per-label conversions and codec support). A workaround is available. Domain names cannot exceed 253 characters in length. If this length limit is enforced prior to passing the domain to the idna.encode() function, it should no longer consume significant resources. This is triggered by arbitrarily large inputs that would not occur in normal usage, but may be passed to the library assuming there is no preliminary input validation by the higher-level application.
The incremental HTML parser (html.parser.HTMLParser) allows for CPU denial-of-service through repeated unterminated markup declarations when processing uncontrolled data.
Impact
Since Requests v2.3.0, Requests has been vulnerable to potentially leaking Proxy-Authorization headers to destination servers, specifically during redirects to an HTTPS origin. This is a product of how rebuildproxies is used to recompute and reattach the Proxy-Authorization header to requests when redirected. Note this behavior has only been observed to affect proxied requests when credentials are supplied in the URL user information component (e.g. https://username:password@proxy:8080).
Current vulnerable behavior(s):
1. HTTP → HTTPS: leak 2. HTTPS → HTTP: no leak 3. HTTPS → HTTPS: leak 4. HTTP → HTTP: no leak
For HTTP connections sent through the proxy, the proxy will identify the header in the request itself and remove it prior to forwarding to the destination server. However when sent over HTTPS, the Proxy-Authorization header must be sent in the CONNECT request as the proxy has no visibility into further tunneled requests. This results in Requests forwarding the header to the destination server unintentionally, allowing a malicious actor to potentially exfiltrate those credentials.
The reason this currently works for HTTPS connections in Requests is the Proxy-Authorization header is also handled by urllib3 with our usage of the ProxyManager in adapters.py with proxymanagerfor. This will compute the required proxy headers in proxyheaders and pass them to the Proxy Manager, avoiding attaching them directly to the Request object. This will be our preferred option going forward for default usage.
Patches Starting in Requests v2.31.0, Requests will no longer attach this header to redirects with an HTTPS destination. This should have no negative impacts on the default behavior of the library as the proxy credentials are already properly being handled by urllib3's ProxyManager.
For users with custom adapters, this may be potentially breaking if you were already working around this behavior. The previous functionality of rebuildproxies doesn't make sense in any case, so we would encourage any users impacted to migrate any handling of Proxy-Authorization directly into their custom adapter.
Workarounds For users who are not able to update Requests immediately, there is one potential workaround.
You may disable redirects by setting allowredirects to False on all calls through Requests top-level APIs. Note that if you're currently relying on redirect behaviors, you will need to capture the 3xx response codes and ensure a new request is made to the redirect destination. import requests r = requests.get('http://github.com/', allowredirects=False)
Credits
This vulnerability was discovered and disclosed by the following individuals.
Dennis Brinkrolf, Haxolot (https://haxolot.com/) Tobias Funke, (tobiasfunke93@gmail.com)
If the value passed to os.path.expandvars() is user-controlled a performance degradation is possible when expanding environment variables.
The imaplib module, when passed a user-controlled command, can have additional commands injected using newlines. Mitigation rejects commands containing control characters.
The poplib module, when passed a user-controlled command, can have additional commands injected using newlines. Mitigation rejects commands containing control characters.
Impact An out-of-bounds write may be triggered when loading a specially crafted PSD image. Pillow >= 10.3.0 users are affected.
Patches Pillow 12.1.1 will be released shortly with a fix for this.
Workarounds Image.open() has a formats parameter that can be used to prevent PSD images from being opened.
References Pillow 12.1.1 will add release notes at https://pillow.readthedocs.io/en/stable/releasenotes/index.html
Last updated 6 July 2026