Information Exposure Affecting pyload-ng package, versions [0,0.5.0b3.dev100)


Severity

Recommended
0.0
medium
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

EPSS
0.34% (26th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-PYTHON-PYLOADNG-16700035
  • published15 May 2026
  • disclosed6 May 2026
  • creditUnknown

Introduced: 6 May 2026

CVE-2026-44226  (opens in a new tab)
CWE-209  (opens in a new tab)

How to fix?

Upgrade pyload-ng to version 0.5.0b3.dev100 or higher.

Overview

pyload-ng is a The free and open-source Download Manager written in pure Python

Affected versions of this package are vulnerable to Information Exposure via the global exception handling process in the WebUI. An attacker can obtain sensitive internal implementation details, such as stack traces and source paths, by sending unauthenticated requests to the /web/<path:filename> endpoint that trigger unhandled exceptions.

PoC

#!/usr/bin/env python3
from __future__ import annotations

import re
import shutil
import tempfile
import traceback
from pathlib import Path


ROOT = Path(__file__).resolve().parent / "pyload" / "src" / "pyload"


def read_text(rel: str) -> str:
    return (ROOT / rel).read_text(encoding="utf-8")


def route_has_no_login_required(app_blueprint: str) -> bool:
    m = re.search(
        r'@bp\\.route\\("/web/<path:filename>", endpoint="web"\\)\\s*'
        r"def render\\(filename\\):(?P<body>.*?)(?:\\n\\n@bp\\.route|\\Z)",
        app_blueprint,
        re.DOTALL,
    )
    if not m:
        return False
    block_start = max(0, m.start() - 200)
    block = app_blueprint[block_start:m.end()]
    return "@login_required(" not in block


def main() -> None:
    workdir = Path(tempfile.mkdtemp(prefix="pyload-traceback-infoleak-"))
    try:
        app_blueprint = read_text("webui/app/blueprints/app_blueprint.py")
        handlers = read_text("webui/app/handlers.py")
        base_template = read_text("webui/app/themes/modern/templates/base.html")

        unauth_web_route = '/web/<path:filename>' in app_blueprint and route_has_no_login_required(app_blueprint)
        user_controlled_template_name = "render_template(filename)" in app_blueprint
        handler_uses_traceback = "traceback.format_exc()" in handlers
        handler_appends_trace = "messages.extend(tb.split('\\n'))" in handlers
        global_exception_handler = "(Exception, handle_exception_error)" in handlers
        template_renders_messages = "{% for message in messages %}" in base_template and "{{message}}" in base_template

        leaked_traceback_keyword = False
        leaked_exception_type = False
        try:
            raise RuntimeError("forced-poc-error")
        except Exception:
            tb = traceback.format_exc()
            messages = [f"Error 500: forced-poc-error"]
            messages.extend(tb.split("\\n"))
            joined = "\\n".join(messages)
            leaked_traceback_keyword = "Traceback (most recent call last)" in joined
            leaked_exception_type = "RuntimeError: forced-poc-error" in joined

        repro_success = all(
            [
                unauth_web_route,
                user_controlled_template_name,
                handler_uses_traceback,
                handler_appends_trace,
                global_exception_handler,
                template_renders_messages,
                leaked_traceback_keyword,
                leaked_exception_type,
            ]
        )

        print("unauth_web_route=", unauth_web_route)
        print("user_controlled_template_name=", user_controlled_template_name)
        print("handler_uses_traceback=", handler_uses_traceback)
        print("handler_appends_trace=", handler_appends_trace)
        print("global_exception_handler=", global_exception_handler)
        print("template_renders_messages=", template_renders_messages)
        print("leaked_traceback_keyword=", leaked_traceback_keyword)
        print("leaked_exception_type=", leaked_exception_type)
        print("traceback_infoleak_repro_success=", repro_success)
    finally:
        shutil.rmtree(workdir, ignore_errors=True)
        print("cleanup_done=True")


if __name__ == "__main__":
    main()

CVSS Base Scores

version 4.0
version 3.1