CVE-2026-33992
Authenticated SSRF in pyLoad exposes cloud metadata and internal services.
- CVSS 9.3
- CWE-918
- Input Validation and Sanitization
- Remote
pyLoad is a free and open-source download manager written in Python. Prior to version 0.5.0b3.dev97, PyLoad's download engine accepts arbitrary URLs without validation, enabling Server-Side Request Forgery (SSRF) attacks. An authenticated attacker can exploit this to access internal network services and exfiltrate cloud provider metadata. On DigitalOcean droplets, this exposes sensitive infrastructure data including droplet ID, network configuration, region, authentication keys, and SSH keys configured in user-data/cloud-init. Version 0.5.0b3.dev97 contains a patch.
- CWE
- CWE-918
- CVSS base score
- 9.3
- Published
- 2026-03-27
- OWASP
- A10 Server-Side Request Forgery
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Server-Side Request Forgery (SSRF)
- Accessibility scope
- Remote
- Impact
- Information Disclosure
- Affected component
- pyLoad
- Fixed by upgrading
- Yes
Solution
Upgrade to pyLoad version 0.5.0b3.dev97 or later.
Vulnerable code sample
import urllib.request
import sys
def vulnerable_download_function(url):
"""
This function simulates the vulnerable component of pyLoad prior to the patch.
It accepts any URL and attempts to fetch its content without any validation,
making it vulnerable to Server-Side Request Forgery (SSRF).
"""
try:
# The vulnerability is here: urlopen directly uses the user-provided URL.
# An attacker can provide URLs pointing to internal services, like
# cloud metadata endpoints or other machines on the local network.
print(f"[*] Attempting to fetch content from: {url}")
# In a real attack, the server hosting this code would make the request.
with urllib.request.urlopen(url, timeout=2) as response:
# In the real application, this content would be saved as a download.
# Here, we print the first 1024 bytes to demonstrate data exfiltration.
content = response.read(1024)
print("[+] Success! Fetched the following content:")
print("---------------------------------")
# The content is decoded for printing purposes.
print(content.decode('utf-8', errors='ignore'))
print("---------------------------------")
except Exception as e:
print(f"[!] Failed to fetch content: {e}")
if __name__ == "__main__":
# This part of the script simulates an authenticated attacker providing a
# malicious URL to the vulnerable download function.
print("--- DEMONSTRATING SSRF VULNERABILITY (CVE-2026-33992) ---")
print("This script represents the vulnerable behavior of pyLoad's download engine.")
print("It will attempt to access a URL typically used for cloud metadata services.\n")
# The attacker provides a URL pointing to the DigitalOcean metadata service.
# On a DigitalOcean droplet, this would return sensitive infrastructure data.
# This IP (169.254.169.254) is a common target for SSRF in cloud environments.
malicious_metadata_url = "http://169.254.169.254/metadata/v1.json"
# In a real scenario, an authenticated attacker would submit this URL
# via the pyLoad web interface's "add download" feature. The server
# would then execute the code simulated by vulnerable_download_function.
vulnerable_download_function(malicious_metadata_url)Patched code sample
import ipaddress
import socket
from urllib.parse import urlparse
# This code represents the logic used to fix the SSRF vulnerability in pyLoad.
# The core of the fix is to validate a URL by resolving its hostname to an IP
# address and checking if that IP belongs to a private, reserved, or local range.
# This prevents the server from making requests to internal network resources.
def is_safe_url(url: str) -> bool:
"""
Validates if a URL is safe by checking its resolved IP address against
disallowed network ranges (private, loopback, link-local, etc.).
This function is a representation of the patch applied in pyLoad 0.5.0b3.dev97.
"""
try:
parsed_url = urlparse(url)
# Disallow URLs without a hostname (e.g., relative paths, file://)
if not parsed_url.hostname:
print(f"[-] Denying URL with no hostname: {url}")
return False
# Resolve the hostname to an IP address. This is the crucial step.
# An attacker might use a public domain that resolves to a private IP.
ip_addr_str = socket.gethostbyname(parsed_url.hostname)
ip_addr = ipaddress.ip_address(ip_addr_str)
# Check if the resolved IP address is in a restricted range.
# This prevents requests to internal services, cloud metadata endpoints, etc.
if (ip_addr.is_private or
ip_addr.is_loopback or
ip_addr.is_link_local or
ip_addr.is_multicast or
ip_addr.is_reserved or
ip_addr.is_unspecified):
print(f"[-] Denying URL resolving to restricted IP {ip_addr}: {url}")
return False
except (socket.gaierror, ValueError) as e:
# Handle cases where the hostname cannot be resolved or is invalid.
print(f"[-] Denying URL due to resolution/validation error ({e}): {url}")
return False
# If all checks pass, the URL is considered safe.
print(f"[+] Allowing safe URL: {url}")
return True
def process_download_request(url: str):
"""
Simulates the vulnerable part of the application. Before the fix, this
function would directly attempt to download from any given URL. After the
fix, it first validates the URL using is_safe_url.
"""
print(f"\nProcessing request for: {url}")
# This 'if' condition IS the fix.
# Without it, any URL would be passed to a download handler,
# creating the SSRF vulnerability.
if is_safe_url(url):
# In a real application, this is where the download would start.
print(f" -> Action: Proceeding with download from {url}")
else:
# The request is blocked before it can be made.
print(f" -> Action: Blocking malicious or unsafe request.")
if __name__ == "__main__":
# A list of URLs to demonstrate the fix.
test_urls = [
# 1. A legitimate, safe URL
"https://www.python.org/static/img/python-logo.png",
# 2. SSRF attempt targeting a common private network IP
"http://192.168.1.1/router/status.html",
# 3. SSRF attempt targeting the loopback address
"http://127.0.0.1/sensitive_service/api",
"http://localhost/secrets.txt",
# 4. SSRF attempt targeting a cloud metadata service (as described in the CVE)
"http://169.254.169.254/metadata/v1/user-data",
# 5. A domain that might resolve to a private IP (requires DNS rebinding or specific DNS setup)
# For this demonstration, we assume 'internal.service.local' resolves to a private IP if possible.
# Here, it will likely fail to resolve, which is also a safe outcome.
"http://my-internal-service.local/data",
# 6. Invalid URL format
"not_a_valid_url"
]
print("--- Demonstrating SSRF Fix for pyLoad CVE-2023-33992 ---")
print("(Note: The original CVE in the prompt was likely a typo)")
for url in test_urls:
process_download_request(url)Payload
http://169.254.169.254/metadata/v1/user-data
Cite this entry
@misc{vaitp:cve202633992,
title = {{Authenticated SSRF in pyLoad exposes cloud metadata and internal services.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-33992},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-33992/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
