Oct 9, 2026·7 min read·6 visits
Low-privilege users can access administrative credential verification endpoints to brute-force the administrator password using a binary oracle and timing side-channel.
An authorization bypass and credential oracle vulnerability in pyload-ng allows authenticated users with minimal or no privileges to brute-force the administrator password. This is achieved through sensitive API methods exposed globally combined with a non-constant-time password hash comparison algorithm.
The application pyload-ng is a popular Python-based download manager designed to run on servers and network-attached storage systems. It exposes a web user interface (WebUI) containing several API endpoints for remote administration, download scheduling, and credential management. In systems designed with multi-user setups, access control boundaries must be maintained strictly to prevent lower-privileged users from accessing administrative operations.
This vulnerability, tracked under GHSA-68W4-83FH-F2W8, represents an authorization bypass chain in pyLoad's API router. The core weakness lies in exposing the sensitive administrative query endpoints getUserData and get_userdata to any authenticated session, regardless of its access control configuration. This is classified under CWE-862 (Missing Authorization) and CWE-287 (Improper Authentication).
Because these endpoints verify user credentials and return full user schemas, they function as a highly predictable binary validation oracle. Any authenticated adversary, even with a guest account, can query these endpoints to systematically extract administrative hashes or perform brute-force validation against administrative accounts without encountering standard access limits.
In typical deployments, standard users are often allowed to submit download requests under lower permission sets. Exposing administrative methods to such users breaks the principle of least privilege. This bypass path allows immediate escalation to global administrator, bypassing the isolation of user roles.
The core security flaw resides in how pyLoad-ng evaluates API permission masks. Authorization permissions are checked using a bitmask comparison where the user's role mask is compared with the target function's required permission decorator. The permission Perms.ANY is defined internally as a null bitmask (value 0). During evaluation, the check user_perms & required_perms == required_perms simplifies to user_perms & 0 == 0, which mathematically resolves to True for every user, including those with zero privileges.
The endpoints getUserData and get_userdata take a username and a cleartext password as input arguments, invoking self.check_auth internally. If the credentials are valid, the endpoints serialize and return a fully populated data object representing the queried user. If invalid, they return an empty wrapper. This behavior creates a clean binary oracle for credentials validation.
Additionally, a password comparison side-channel (CWE-208) exists in the database routine located in src/pyload/core/database/user_database.py. The comparison of the computed password hash and the stored password hash was performed using Python's standard == string equality operator. Since this operator performs a non-constant-time byte-by-byte comparison, it terminates early on the first mismatched byte, creating an observable timing side-channel.
The following diagram maps the logical bypass and query validation path:
Before the patch, the administrative methods were configured in src/pyload/core/api/__init__.py using the @permission(Perms.ANY) decorator, as shown below:
#: Old API
@permission(Perms.ANY)
@get
def getUserData(self, username: str, password: str) -> OldUserData:
"""
"""
if self.check_auth(username, password):
return OldUserData(self.pyload.db.get_user_data(username))
else:
return OldUserData()
@permission(Perms.ANY)
@get
def get_userdata(self, username: str, password: str) -> UserData:
"""
"""
if self.check_auth(username, password):
return UserData(self.pyload.db.get_user_data(username))
else:
return UserData()The corresponding validation routine in src/pyload/core/database/user_database.py implemented password verification using standard string comparison:
def _check_password(hashed, clear):
salt = hashed[:32]
to_compare = _salted_password(clear, salt)
return hashed == to_compareThe official fix in commit b99d2a2f06135363ceb0aab16aac5025f138e658 remediated both issues. First, it stripped the @permission(Perms.ANY) decorator from both endpoints, forcing them to fall back to the default Perms.ADMIN requirements. Second, it imported the hmac module and modified the comparison block to use constant-time matching:
import hmac
def _check_password(hashed, clear):
salt = hashed[:32]
to_compare = _salted_password(clear, salt)
# Secure comparison prevents timing attacks
return hmac.compare_digest(hashed, to_compare)This remediation effectively closes the authorization bypass path because removing the decorator forces the fallback to strict administrative checks. Additionally, the constant-time mitigation secures password validation against side-channel attacks. Developers must ensure that other endpoints decorated with Perms.ANY do not perform secondary validation patterns that could yield similar information disclosure.
To exploit this vulnerability, an attacker must obtain an authenticated session on the target pyLoad-ng instance. This requirement is fulfilled in multi-user deployments, environments where user registration is allowed, or where a low-privilege service account has been leaked or compromised. Once logged in, the application assigns a session identifier cookie that accompanies all subsequent requests.
An attacker targeting the admin account crafts HTTP GET requests to /api/getUserData or /api/get_userdata, populating the username query parameter as admin and iterating through candidate passwords in the password parameter. The server handles these requests internally, checking each password without locking out the target administrator account, as the API bypasses standard login rate-limiting controls.
A failed password attempt yields an empty wrapper structure such as {"name": ""}, while a successful query returns a structured JSON payload containing real user details such as the administrator's email, storage limits, and system configurations. This difference allows the attacker's script to easily detect the correct password and terminate the loop.
Because the API operates over HTTP and does not invoke slow user session initiation overheads for each check, thousands of credential combinations can be tested per minute depending on network latency. This makes dictionary-based brute force extremely efficient and highly reliable.
Gaining full administrative access to pyLoad-ng grants the attacker complete authority over the application state. The administrative console allows users to modify core settings, configure external download scripts, access sensitive credential configurations, and view the server's filesystem layout.
pyLoad-ng supports the execution of external reconnect scripts and download-trigger scripts when certain system events occur. An administrative attacker can write arbitrary scripts to the local disk and configure pyLoad-ng to execute them, leading to complete shell compromise on the host operating system under the privileges of the running daemon.
The attack is network-bound (AV:N) and trivial to perform (AC:L), requiring only minimal user credentials (PR:L) and zero human intervention (UI:N). The scope remains unchanged (S:U), but the impact across Confidentiality, Integrity, and Availability is maximized (C:H/I:H/A:H) due to the administrative capabilities and subsequent system execution paths.
As of the current advisory, there is no official CVE ID allocated, preventing direct mapping within standard automated threat scanners or EPSS tracking. This makes it likely that legacy, unpatched pyLoad instances will remain undetected by traditional corporate vulnerability scanners while remaining exposed to manual or custom-scripted attacks.
The primary fix is to apply the changes contained in commit b99d2a2f06135363ceb0aab16aac5025f138e658. This removes the insecure authorization decorators and incorporates secure hashing comparison. Administrators should ensure their pyload-ng installations are updated to include this commit or any subsequent release branch.
If the software cannot be immediately updated, network administrators must enforce strict access controls. Restricting the pyLoad WebUI via firewall rules, placing it behind a VPN, or forcing host-level authentication controls at the proxy level will prevent unauthorized external requests from interacting with the routing framework.
Security teams can write layer-7 inspection rules to intercept traffic to /api/getUserData and /api/get_userdata. If the incoming request lacks an administrative session token, the WAF should terminate the connection immediately. Rate-limiting rules should also be deployed specifically to these API paths to block automated brute-forcing.
Security operations centers can audit server transaction logs for anomalous volumes of GET requests targeting the /api/getUserData and /api/get_userdata endpoints. An influx of requests from a single source IP with high variation in parameters is a strong indicator of an active brute-force or credential-stuffing attack.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
pyload-ng pyload | All versions prior to commit b99d2a2f06135363ceb0aab16aac5025f138e658 | Commit b99d2a2f06135363ceb0aab16aac5025f138e658 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862, CWE-287, CWE-208 |
| Attack Vector | Network |
| CVSS v3.1 Score | 8.8 (High) |
| EPSS Score | N/A (No mapped CVE) |
| Impact | Full Administrative Compromise / Configuration Arbitrary Manipulation |
| Exploit Status | PoC (Proof of Concept) available |
| CISA KEV Status | Not Listed |
The application does not perform an authorization check when an actor attempts to access a resource or perform an action.
A critical security vulnerability has been identified and patched in the WebUI component of pyLoad, a popular Python-based open-source download manager. This vulnerability allows attackers to completely bypass API rate limits and spoof client IP addresses in audit logs due to unsafe parsing of the X-Forwarded-For HTTP header.
An authentication bypass vulnerability in pyLoad allows unauthenticated remote attackers to gain administrative API access. The vulnerability is caused by a logical flaw in the API key cache validation lookup, where authentication states are cached using only the public key identifier, skipping cryptographic token verification on cache hits.
An authorization bypass vulnerability in Strawberry GraphQL between versions 0.217.0 and 0.326.1 occurs when a synchronous permission handler returns an awaitable object (such as an unawaited coroutine). Due to Python's truthiness rules, the unawaited coroutine is evaluated as True, leading to an immediate bypass of security policies.
An uncontrolled resource consumption vulnerability in Strawberry GraphQL allows unauthenticated remote attackers to trigger a Denial of Service on persistent WebSocket connections using the legacy graphql-ws protocol. When the server enforces max_subscriptions_per_connection, naturally terminating subscriptions are not cleared from memory registries, leading to exhaustion of connection slots.
A high-severity type-confusion vulnerability exists in NearForm fast-jwt prior to version 6.3.0. The vulnerability allows attackers to bypass crucial claim validation steps (such as expiration, issuer, audience, and subject validations) by presenting a validly signed JSON Web Token structured as a JSON array instead of a JSON object. This occurs because the library's decoder fails to reject JSON arrays during type evaluation.
NearForm fast-jwt prior to version 6.3.0 is vulnerable to an input validation flaw where configuring verifier properties (such as clockTolerance, clockTimestamp, and cacheTTL) with non-finite values like Infinity or NaN allows attackers to bypass temporal claim validations, including expiration (exp) and activation (nbf) boundaries. This validation bypass can result in unauthorized session persistence and cache poisoning.