Kubernetes
CVE-2026-40594
MEDIUM
Severity by source
AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:L
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:L
Lifecycle Timeline
4DescriptionGitHub Advisory
Summary
The 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.
Details
The vulnerable code is in src/pyload/webui/app/__init__.py:75-84:
# Dynamically set SESSION_COOKIE_SECURE according to the value of X-Forwarded-Proto
# TODO: Add trusted proxy check
@app.before_request
def set_session_cookie_secure():
x_forwarded_proto = flask.request.headers.get("X-Forwarded-Proto", "")
is_secure = (
x_forwarded_proto.split(',')[0].strip() == "https" or
app.config["PYLOAD_API"].get_config_value("webui", "use_ssl")
)
flask.current_app.config['SESSION_COOKIE_SECURE'] = is_secureThe root cause has two components:
- No origin validation (CWE-346): The
X-Forwarded-Protoheader is read from any client request. This header is only trustworthy when set by a known reverse proxy. WithoutProxyFixmiddleware 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) writesFalseto this config, Thread B (victim) may readFalsewhen Flask'ssave_session()runs in the after_request phase, producing aSet-Cookieresponse without theSecureflag.
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:
# Attacker floods backend directly, bypassing TLS proxy
for i in $(seq 1 200); do
curl -s -H 'X-Forwarded-Proto: http' http://pyload-backend:8000/ &
done
# Meanwhile, a legitimate user behind the TLS proxy receives a session cookie
# During the race window, their Set-Cookie header lacks the Secure flag
# The cookie is then vulnerable to interception over plain HTTPAttack Path 2 - Session Denial of Service (default plain HTTP deployment):
# Attacker causes SESSION_COOKIE_SECURE=True on a plain HTTP server
for i in $(seq 1 200); do
curl -s -H 'X-Forwarded-Proto: https' http://localhost:8000/ &
done
# Concurrent legitimate users receive Set-Cookie with Secure flag
# Browser refuses to send Secure cookies over HTTP
# Users' sessions silently break - they appear logged outThe 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
Secureflag. 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_requesthandler fires before any auth checks.
Recommended Fix
Replace the global config mutation with per-response cookie handling, and add proxy validation:
# Option A: Set Secure flag per-response instead of mutating global config
@app.after_request
def set_session_cookie_secure(response):
# Only trust X-Forwarded-Proto if ProxyFix is configured
is_secure = app.config["PYLOAD_API"].get_config_value("webui", "use_ssl")
if 'Set-Cookie' in response.headers:
# Modify cookie flags per-response, not global config
cookies = response.headers.getlist('Set-Cookie')
response.headers.remove('Set-Cookie')
for cookie in cookies:
if is_secure and 'Secure' not in cookie:
cookie += '; Secure'
response.headers.add('Set-Cookie', cookie)
return response
# Option B (preferred): Use Werkzeug's ProxyFix with explicit trust
from werkzeug.middleware.proxy_fix import ProxyFix
# In App.__new__, before returning:
if trusted_proxy_count:
# from config
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=trusted_proxy_count)
# Then set SESSION_COOKIE_SECURE once at startup based on use_ssl config,
# and let ProxyFix handle X-Forwarded-Proto transparentlyAt 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.
AnalysisAI
Race condition in pyLoad's Flask session cookie handler allows unauthenticated attackers to manipulate the SESSION_COOKIE_SECURE flag globally across all concurrent requests by spoofing the X-Forwarded-Proto header. On deployments behind a TLS-terminating proxy, this enables session cookie downgrade attacks resulting in plaintext cookie transmission; on default plain HTTP deployments, it causes session denial of service by forcing the Secure flag and breaking all concurrent user sessions. The vulnerability requires no authentication and exploits a multi-threaded race window in the Cheroot WSGI server (request_queue_size=512) combined with missing proxy origin validation (acknowledged TODO in code).
Technical ContextAI
pyLoad is a Python-based download manager that uses Flask for its web UI and Cheroot as its multi-threaded WSGI server. The vulnerability exists in the set_session_cookie_secure() before_request handler in src/pyload/webui/app/__init__.py, which reads the X-Forwarded-Proto header without validation and writes directly to Flask's global application configuration object (flask.current_app.config['SESSION_COOKIE_SECURE']). Because Cheroot processes requests concurrently (request_queue_size=512 threads), and Flask's session-save logic runs in the after_request phase on the same thread that processed the before_request phase, a crafted request from Thread A can modify global state before Thread B's after_request handler executes, causing Thread B's response to reflect Thread A's malicious configuration. The root cause is classified as CWE-346 (Origin Validation Error) combined with unsafe multi-threaded access to shared mutable state. No ProxyFix middleware or trusted proxy allowlist exists in the codebase to validate header origin.
RemediationAI
The vendor-recommended fix is to replace global config mutation with per-response cookie handling combined with proxy validation. Immediate action: apply the vendor's patch (available in the GitHub advisory at https://github.com/pyload/pyload/security/advisories/GHSA-mp82-fmj6-f22v) which removes the race-prone before_request handler and uses either Werkzeug ProxyFix with explicit trusted proxy configuration or per-response Set-Cookie manipulation in an after_request handler. If patching is delayed, the most effective workaround is to disable the vulnerable before_request handler entirely by removing or commenting out the set_session_cookie_secure() function in src/pyload/webui/app/__init__.py and setting SESSION_COOKIE_SECURE once at application startup (the existing _configure_session() method already does this); this eliminates the race condition and header spoofing at the cost of losing dynamic SSL detection per-request (acceptable for most deployments where SSL mode does not change at runtime). For Kubernetes/container deployments, restrict network access to the pyLoad backend listener to only the TLS-terminating proxy; deny direct attacker access to port 8000. For plain HTTP deployments (no proxy), understand that SESSION_COOKIE_SECURE cannot be set True without breaking legitimate user sessions, so the security posture depends entirely on network isolation and HTTPS enforcement at the reverse proxy layer. Trade-off: the workaround prevents dynamic per-request SSL mode switching, so environments where users access both HTTP and HTTPS endpoints on the same deployment must be reconfigured to use a single protocol or accept cookies as session-only (HttpOnly flag sufficient without Secure on trusted networks).
More in Kubernetes
View allA critical vulnerability in Kubernetes ingress-nginx controller allows unauthenticated attackers with pod network access
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Kubernetes ingress-nginx contains a configuration injection vulnerability via the mirror-target and mirror-host Ingress
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-url` Ingres
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-tls-match-c
Kubernetes API server in all versions allow an attacker who is able to create a ClusterIP service and set the spec.exter
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Rated critical severity (CVSS 9.9), this vulne
The Kubernetes integration in GitLab Enterprise Edition 11.x before 11.2.8, 11.3.x before 11.3.9, and 11.4.x before 11.4
Kyverno Kubernetes policy engine prior to 1.x has a privilege escalation vulnerability (CVSS 9.9) allowing policy bypass
Kamaji is the Hosted Control Plane Manager for Kubernetes. Rated critical severity (CVSS 9.9), this vulnerability is rem
Jumpserver is a popular open source bastion host, and Koko is a Jumpserver component that is the Go version of coco, ref
String filter bypass in Inspektor Gadget Kubernetes eBPF tooling before fix. Insufficient string escaping enables filter
Same weakness CWE-346 – Origin Validation Error
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-mp82-fmj6-f22v