VYPR
Moderate severityNVD Advisory· Published Feb 6, 2024· Updated May 9, 2025

pyLoad open redirect vulnerability due to improper validation of the is_safe_url function

CVE-2024-24808

Description

pyLoad is an open-source Download Manager written in pure Python. There is an open redirect vulnerability due to incorrect validation of input values when redirecting users after login. pyLoad is validating URLs via the get_redirect_url function when redirecting users at login. This vulnerability has been patched with commit fe94451.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
pyload-ngPyPI
< 0.5.0b3.dev790.5.0b3.dev79

Affected products

1

Patches

1
fe94451dcc2b

fix GHSA-g3cm-qg2v-2hj5 security advisory

https://github.com/pyload/pyloadGammaC0deFeb 5, 2024via ghsa
2 files changed · +24 20
  • src/pyload/webui/app/blueprints/app_blueprint.py+5 5 modified
    @@ -47,7 +47,7 @@ def robots():
     def login():
         api = flask.current_app.config["PYLOAD_API"]
     
    -    next = get_redirect_url(fallback=flask.url_for("app.dashboard"))
    +    next_url = get_redirect_url(fallback="app.dashboard")
     
         if flask.request.method == "POST":
             user = flask.request.form["username"]
    @@ -57,14 +57,14 @@ def login():
             sanitized_user = user.replace("\n", "\\n").replace("\r", "\\r")
             if not user_info:
                 log.error(f"Login failed for user '{sanitized_user}'")
    -            return render_template("login.html", next=next, errors=True)
    +            return render_template("login.html", errors=True)
     
             set_session(user_info)
             log.info(f"User '{sanitized_user}' successfully logged in")
             flask.flash("Logged in successfully")
     
         if is_authenticated():
    -        return flask.redirect(next)
    +        return flask.redirect(next_url)
     
         if api.get_config_value("webui", "autologin"):
             allusers = api.get_all_userdata()
    @@ -74,9 +74,9 @@ def login():
                 # NOTE: Double-check authentication here because if session[name] is empty,
                 #       next login_required redirects here again and all loop out.
                 if is_authenticated():
    -                return flask.redirect(next)
    +                return flask.redirect(next_url)
     
    -    return render_template("login.html", next=next)
    +    return render_template("login.html")
     
     
     @bp.route("/logout", endpoint="logout")
    
  • src/pyload/webui/app/helpers.py+19 15 modified
    @@ -2,10 +2,11 @@
     
     import json
     from functools import wraps
    -from urllib.parse import unquote, urljoin, urlparse
    +from urllib.parse import urljoin, urlparse
     
     import flask
     import flask_themes2
    +import werkzeug.routing.exceptions
     from pyload.core.api import Perms, Role, has_permission
     
     
    @@ -33,22 +34,25 @@ def loads(self, s, **kwargs):
     
     #: Checks if location belongs to same host address
     def is_safe_url(location):
    -    ref_url = urlparse(flask.request.host_url)
    -    test_url = urlparse(urljoin(flask.request.host_url, location))
    -    return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc
    +    location_urlp = urlparse(location)
    +    #: if relative URL then must start with "/"
    +    if not location_urlp.netloc and location[0] != "/":
    +        return False
    +    host_urlp = urlparse(flask.request.host_url)
    +    test_urlp = urlparse(urljoin(flask.request.host_url, location))
    +    return test_urlp.scheme in ('http', 'https') and host_urlp.netloc == test_urlp.netloc
     
     
     def get_redirect_url(fallback=None):
    -    login_url = urljoin(flask.request.url_root, flask.url_for('app.login'))
    -    request_url = unquote(flask.request.url)
    -    for location in flask.request.values.get("next"), flask.request.referrer:
    -        if not location:
    -            continue
    -        if location in (request_url, login_url):  # don't redirect to same location
    -            continue
    -        if is_safe_url(location):
    -            return location
    -    return fallback
    +    next_arg = flask.request.values.get("next")
    +    redirect_url = flask.url_for(fallback)
    +    if next_arg and next_arg != "login":  # don't redirect to same location
    +        try:
    +            redirect_url = flask.url_for(f"app.{next_arg}")
    +        except werkzeug.routing.exceptions.BuildError:
    +            pass
    +
    +    return urljoin(flask.request.url_root, redirect_url)
     
     
     def render_base(messages):
    @@ -206,7 +210,7 @@ def wrapper(*args, **kwargs):
                     else:
                         location = flask.url_for(
                             "app.login",
    -                        next=flask.request.url
    +                        next=flask.request.endpoint.split(".")[-1]
                         )
                         response = flask.redirect(location)
     
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.