GHSA-r7mc-x6x7-cqxx pyLoad SETTINGS Permission Users Can Achieve Remote Code Execution via Unrestricted Reconnect Script Configuration
SummaryThe `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.DetailsThe vulnerability chain spans two components:**1. Unrestricted config write — `src/pyload/core/api/__init__.py:210-243`**The `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.**2. Arbitrary script execution — `src/pyload/core/managers/thread_manager.py:157-199`**The `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.**3. Attacker also controls timing via same SETTINGS permission**The 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.**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 `get_config()`Redirect syslog to an attacker-controlled server (`log.syslog_host`/`log.syslog_port`)Disable SSL (`webui.use_ssl=False`), rebind to `0.0.0.0` (`webui.host`)Modify SSL certificate/key paths to enable MITMPoC**Step 1: Set reconnect script to an attacker-controlled executable**Via API:Via Web UI:**Step 2: Enable reconnect and set timing window****Step 3: Script executes when thread manager calls `try_reconnect()`**The 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`.**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 `get_config()`**Network reconfiguration**: SETTINGS users can disable SSL, change bind address, redirect logging, and modify other security-critical network settingsRecommended FixAdd an allowlist or category-level restriction in `set_config_value()` that prevents non-admin users from modifying security-critical options:Additionally, consider validating the `reconnect.script` path against an allowlist of directories or requiring admin approval for script path changes.
CVSS v3.1 score: 7.5