GHSA-mp82-fmj6-f22v: pyLoad has a Session Cookie Security Downgrade via Untrusted X-Forwarded-Proto Header Spoofing (Global State Race Condition)
SummaryThe `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.DetailsThe vulnerable code is in `src/pyload/webui/app/__init__.py:75-84`:The root cause has two components:**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.**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.The Cheroot WSGI server is configured with `request_queue_size=512` in `src/pyload/webui/webserver_thread.py:46`, confirming concurrent multi-threaded request processing.No `ProxyFix` or equivalent middleware is configured anywhere in the codebase (confirmed via codebase-wide search).PoC**Attack Path 1 — Cookie Security Downgrade (behind TLS-terminating proxy, `use_ssl=False`):**An 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`:**Attack Path 2 — Session Denial of Service (default plain HTTP deployment):**The second attack path works against the default configuration (`use_ssl=False`) and requires no special network position.Impact**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.**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.**No authentication required:** Both attack paths are fully unauthenticated — the `before_request` handler fires before any auth checks.Recommended FixReplace the global config mutation with per-response cookie handling, and add proxy validation:At 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.
CVSS v3.1: 4.8