{"id":"CVE-2026-45306","aliases":["PYSEC-2026-2998"],"url":"https://o3.security/vulnerability/CVE-2026-45306","summary":"pyLoad Has Incomplete Fix for CVE-2026-33509 -storage_folder Bypass via Session Directory in pyLoad","details":"## Summary\nThe fix for CVE-2026-33509 prevents setting `storage_folder` inside `PKGDIR` or `userdir`, but does NOT protect the Flask session directory (`/tmp/pyLoad/flask`). An authenticated attacker can set `storage_folder` to the session directory and download session files of other users via `/files/get/`, leading to account takeover.\n\n## Details\n\nThe fix in `src/pyload/core/api/__init__.py`:\n\n```python\ndirectories = [PKGDIR, userdir]\nif any(directories[0].startswith(d) for d in directories[1:]):\n    return  # blocked\n```\n\nBut the Flask session directory is:\n```python\nsession_storage_path = os.path.join(api.get_cachedir(), \"flask\")\n# = /tmp/pyLoad/flask  ← NOT blocked by fix\n```\n\n## Attack Chain\n\n1. Attacker (admin) sets `storage_folder = /tmp/pyLoad/flask`\n2. Fix does NOT block this — `/tmp/pyLoad/flask` not inside `PKGDIR` or `userdir`\n3. Attacker requests `GET /files/get/<victim_session_filename>`\n4. `send_from_directory('/tmp/pyLoad/flask', session_file)` serves victim's session\n5. Attacker uses stolen session → **Account Takeover**\n\n## PoC\n\n<img width=\"592\" height=\"408\" alt=\"POC\" src=\"https://github.com/user-attachments/assets/936b9f56-325b-437d-9edd-e0d5bb995187\" />\n\n```python\nimport os\n\nPKGDIR = \"/usr/lib/python3/dist-packages/pyload\"\nuserdir = os.path.expanduser(\"~/.pyload\")\nsession_dir = \"/tmp/pyLoad/flask\"\n\ncorrect_case = lambda x: x\ndirectories = [\n    correct_case(os.path.join(os.path.realpath(d), \"\"))\n    for d in [session_dir, PKGDIR, userdir]\n]\nblocked = any(directories[0].startswith(d) for d in directories[1:])\n\nprint(f\"Fix blocks session_dir: {blocked}\")\n# Output: Fix blocks session_dir: False  ← BYPASS CONFIRMED\n```\n\n## Impact\nAuthenticated admin can steal sessions of other users → Account Takeover.\n\n## Suggested Fix\n```python\nblocked_dirs = [PKGDIR, userdir, api.get_cachedir()]\ndirectories = [\n    os.path.join(os.path.realpath(d), \"\")\n    for d in [value] + blocked_dirs\n]\nif any(directories[0].startswith(d) for d in directories[1:]):\n    return\n```","published":"2026-05-14T20:17:27Z","modified":"2026-07-13T16:43:32.057393623Z","cvss":{"score":6.5,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N"},"epss":{"score":0.00234,"percentile":0.14337,"asOf":"2026-08-09"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"pyload-ng","fixedVersion":null}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/pyload/pyload/security/advisories/GHSA-w727-595x-pc3r"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-45306"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-r7mc-x6x7-cqxx"},{"type":"PACKAGE","url":"https://github.com/pyload/pyload"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-07-13T16:43:32.057393623Z"}}