GHSA-r44w-v6gf-x3p6: Pyload ng Authentication Bypass Vulnerability

HIGH
CVSS 8.1
CWE-287
Published
Advisory Summary

GHSA-r44w-v6gf-x3p6 is a HIGH (CVSS 8.1) authentication bypass vulnerability (CWE-287: Improper Authentication) affecting Pyload ng libraries in the PyPI ecosystem. The issue involves pyload has an authentication bypass in api key validation (check_apikey cache). Remediation is available by upgrading affected packages to version 0.5.0b3.dev101.

GHSA-r44w-v6gf-x3p6 at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-r44w-v6gf-x3p6
Severity HIGH
CVSS v3.1 Base Score 8.1
CWE Classification CWE-287: Improper Authentication
Affected Product Pyload ng
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 8.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix GHSA-r44w-v6gf-x3p6

To remediate this vulnerability, upgrade all affected Pyload ng dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

pyload-ng fixed: 0.5.0b3.dev101
pip install pyload-ng>=0.5.0b3.dev101
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show pyload-ng

How to Check if You Are Affected

To determine whether your Python environment is affected by GHSA-r44w-v6gf-x3p6, inspect your installed packages using pip:

pip show pyload-ng

Analyze the terminal output to locate any version of Pyload ng in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.5.0b3.dev101), your application is affected.

Note: The pip show pyload-ng command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-287: Improper Authentication, where when an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct. In Pyload ng, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary The API-key cache in `check_apikey()` allows an attacker to authenticate with a **forged API key** as long as the legitimate key for the same `key_id` has been used recently. On a cache hit, the API key **secret is never verified**, resulting in a complete authentication bypass during the cache lifetime. --- # Affected Components - `src/pyload/core/api/init.py` - `Api.check_apikey()` - `src/pyload/core/database/apikey_database.py` - `check_apikey()` - `_check_key()` The cache is used by normal API requests through: - `src/pyload/webui/app/helpers.py` which calls: ```python api.check_apikey(api_key) ``` without providing a `ttl`, meaning the default **300-second cache** is always enabled. --- # Root Cause Successful API key validations are cached in: ```python self._apikey_cache ``` using the following structure: ```python { key_id: (timestamp, cached_data) } ``` The cache key is based **only on `key_id`**, and that value is parsed directly from the user-supplied API key rather than being obtained from a trusted lookup. When a cache hit occurs within the TTL, `check_apikey()` returns: ```python { "success": True, "data": cached_data } ``` after checking only: - `expires_at` At no point on this execution path is the supplied secret: ```text apikey[-43:] ``` compared against the stored key hash. --- The actual secret verification exists only in: ```python _check_key() ``` which correctly uses: ```python hmac.compare_digest() ``` However, this function is only reached on a **cache miss** through the database layer's `check_apikey()` implementation. Furthermore, the cached object cannot be used for verification because it intentionally does **not** include the stored key hash. The cached record contains only: - `id` - `user_id` - `name` - `created_at` - `expires_at` - `last_used` Since `key_hash` is absent, the cache lacks the information required to validate the presented secret. As a result, once a legitimate request populates the cache, every subsequent request using the same `key_id` within the 300-second cache window is accepted **without validating the secret**. --- # Impact `key_id` values are small sequential integers assigned when API keys are created (1, 2, 3, ...), making them trivial to enumerate. The API key format is also publicly reconstructable from the source code. An attacker therefore does **not** need to know any valid API key secret. They only need a `key_id` whose legitimate key has been used within the previous five minutes, which is likely on an actively used deployment. During that cache window, a forged API key follows exactly the same authentication path as a legitimate key and inherits the associated user's permissions. This results in a **complete remote authentication bypass**. I would classify the issue as **Critical** severity. --- # Estimated CVSS v3.1 ``` AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H ``` (`AC:H` only because successful exploitation depends on the cache already containing an entry.) --- # Reproduction ### 1. Create an administrator account. --- ### 2. Generate an API key. Example: ```text pl_11<43-character-secret> ``` where: ``` key_id = 1 ``` --- ### 3. Send a legitimate authenticated request. ```bash curl \ -H "X-API-Key: pl_11<real-43-char-secret>" \ http://127.0.0.1:8000/api/status ``` Expected response: ```text HTTP/1.1 200 OK ``` --- ### 4. Within 300 seconds, send the same request using a forged API key. ```bash curl \ -H "X-API-Key: pl_11xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ http://127.0.0.1:8000/api/status ``` Observed response: ```text HTTP/1.1 200 OK ``` The request succeeds even though the API key secret is entirely incorrect. --- # Control Test If the forged API key is sent **before** any legitimate request has populated the cache, the server correctly returns: ```text HTTP/1.1 401 Unauthorized ``` The only difference between the failing and succeeding forged request is whether the cache already contains an entry for that `key_id`. This isolates the vulnerability specifically to the cache-hit path. --- # Suggested Fix Cache hits should **never replace secret verification**. Possible approaches include: - Store a value derived from the complete API key (or its hash) in the cache and verify it using `hmac.compare_digest()` on every cache hit before returning success. - Alternatively, key the cache using a value derived from the **entire API key secret** (for example, a cryptographic hash of the complete API key) rather than using only `key_id`. Regardless of implementation, the security invariant should remain: > **The API key secret must be validated on every authenticated request, regardless of whether the cache is hit or missed.**

GHSA-r44w-v6gf-x3p6 Affected Pyload ng Versions

1 component(s)
Fixed Versions:
0.5.0b3.dev101
Product / Package Ecosystem Affected Versions Fixed Version
pyload-ng
PyPI
< 0.5.0b3.dev101
0.5.0b3.dev101

References

Frequently Asked Questions

What is GHSA-r44w-v6gf-x3p6?
GHSA-r44w-v6gf-x3p6 is a security vulnerability in Pyload ng involving pyLoad has an authentication bypass in API key validation (check_apikey cache) under CWE-287: Improper Authentication.
Which Pyload ng versions are affected?
Affected versions include releases prior to 0.5.0b3.dev101 across affected packages: pyload-ng.
What version fixes GHSA-r44w-v6gf-x3p6?
Upgrading to 0.5.0b3.dev101 (or the latest patched release for your respective branch) resolves the vulnerability.
Is pyload-ng affected?
Yes, pyload-ng is affected in releases prior to 0.5.0b3.dev101. Upgrade your dependency to 0.5.0b3.dev101 or later.
What is the CVSS score of GHSA-r44w-v6gf-x3p6?
GHSA-r44w-v6gf-x3p6 has a CVSS v3.1 base score of 8.1 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with GHSA-r44w-v6gf-x3p6?
GHSA-r44w-v6gf-x3p6 is classified under CWE-287: Improper Authentication (When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.).
How can I check PyPI dependencies for GHSA-r44w-v6gf-x3p6?
Run the dependency tree command: 'pip show pyload-ng'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-r44w-v6gf-x3p6",
  "modified" : "2026-10-09T16:43:55Z",
  "published" : "2026-10-09T16:43:55Z",
  "aliases" : [ ],
  "summary" : "pyLoad has an authentication bypass in API key validation (check_apikey cache)",
  "details" : "## Summary\n\nThe API-key cache in `check_apikey()` allows an attacker to authenticate with a **forged API key** as long as the legitimate key for the same `key_id` has been used recently.\n\nOn a cache hit, the API key **secret is never verified**, resulting in a complete authentication bypass during the cache lifetime.\n\n---\n\n# Affected Components\n\n- `src/pyload/core/api/init.py`\n  - `Api.check_apikey()`\n\n- `src/pyload/core/database/apikey_database.py`\n  - `check_apikey()`\n  - `_check_key()`\n\nThe cache is used by normal API requests through:\n\n- `src/pyload/webui/app/helpers.py`\n\nwhich calls:\n\n```python\napi.check_apikey(api_key)\n```\n\nwithout providing a `ttl`, meaning the default **300-second cache** is always enabled.\n\n---\n\n# Root Cause\n\nSuccessful API key validations are cached in:\n\n```python\nself._apikey_cache\n```\n\nusing the following structure:\n\n```python\n{\n    key_id: (timestamp, cached_data)\n}\n```\n\nThe cache key is based **only on `key_id`**, and that value is parsed directly from the user-supplied API key rather than being obtained from a trusted lookup.\n\nWhen a cache hit occurs within the TTL, `check_apikey()` returns:\n\n```python\n{\n    \"success\": True,\n    \"data\": cached_data\n}\n```\n\nafter checking only:\n\n- `expires_at`\n\nAt no point on this execution path is the supplied secret:\n\n```text\napikey[-43:]\n```\n\ncompared against the stored key hash.\n\n---\n\nThe actual secret verification exists only in:\n\n```python\n_check_key()\n```\n\nwhich correctly uses:\n\n```python\nhmac.compare_digest()\n```\n\nHowever, this function is only reached on a **cache miss** through the database layer's `check_apikey()` implementation.\n\nFurthermore, the cached object cannot be used for verification because it intentionally does **not** include the stored key hash.\n\nThe cached record contains only:\n\n- `id`\n- `user_id`\n- `name`\n- `created_at`\n- `expires_at`\n- `last_used`\n\nSince `key_hash` is absent, the cache lacks the information required to validate the presented secret.\n\nAs a result, once a legitimate request populates the cache, every subsequent request using the same `key_id` within the 300-second cache window is accepted **without validating the secret**.\n\n---\n\n# Impact\n\n`key_id` values are small sequential integers assigned when API keys are created (1, 2, 3, ...), making them trivial to enumerate.\n\nThe API key format is also publicly reconstructable from the source code.\n\nAn attacker therefore does **not** need to know any valid API key secret.\n\nThey only need a `key_id` whose legitimate key has been used within the previous five minutes, which is likely on an actively used deployment.\n\nDuring that cache window, a forged API key follows exactly the same authentication path as a legitimate key and inherits the associated user's permissions.\n\nThis results in a **complete remote authentication bypass**.\n\nI would classify the issue as **Critical** severity.\n\n---\n\n# Estimated CVSS v3.1\n\n```\nAV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H\n```\n\n(`AC:H` only because successful exploitation depends on the cache already containing an entry.)\n\n---\n\n# Reproduction\n\n### 1. Create an administrator account.\n\n---\n\n### 2. Generate an API key.\n\nExample:\n\n```text\npl_11<43-character-secret>\n```\n\nwhere:\n\n```\nkey_id = 1\n```\n\n---\n\n### 3. Send a legitimate authenticated request.\n\n```bash\ncurl \\\n  -H \"X-API-Key: pl_11<real-43-char-secret>\" \\\n  http://127.0.0.1:8000/api/status\n```\n\nExpected response:\n\n```text\nHTTP/1.1 200 OK\n```\n\n---\n\n### 4. Within 300 seconds, send the same request using a forged API key.\n\n```bash\ncurl \\\n  -H \"X-API-Key: pl_11xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\" \\\n  http://127.0.0.1:8000/api/status\n```\n\nObserved response:\n\n```text\nHTTP/1.1 200 OK\n```\n\nThe request succeeds even though the API key secret is entirely incorrect.\n\n---\n\n# Control Test\n\nIf the forged API key is sent **before** any legitimate request has populated the cache, the server correctly returns:\n\n```text\nHTTP/1.1 401 Unauthorized\n```\n\nThe only difference between the failing and succeeding forged request is whether the cache already contains an entry for that `key_id`.\n\nThis isolates the vulnerability specifically to the cache-hit path.\n\n---\n\n# Suggested Fix\n\nCache hits should **never replace secret verification**.\n\nPossible approaches include:\n\n- Store a value derived from the complete API key (or its hash) in the cache and verify it using `hmac.compare_digest()` on every cache hit before returning success.\n\n- Alternatively, key the cache using a value derived from the **entire API key secret** (for example, a cryptographic hash of the complete API key) rather than using only `key_id`.\n\nRegardless of implementation, the security invariant should remain:\n\n> **The API key secret must be validated on every authenticated request, regardless of whether the cache is hit or missed.**",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "pyload-ng"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.5.0b3.dev101"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/pyload/pyload/security/advisories/GHSA-r44w-v6gf-x3p6"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pyload/pyload/commit/00d1372510f915f843b1574a3f1b28fbb724a42e"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/pyload/pyload"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-287" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-09T16:43:55Z",
    "nvd_published_at" : null
  }
}