diff --git a/CHANGES.txt b/CHANGES.txt index 722e14e3..3da2e991 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,19 @@ Unreleased ---------- +Security Fix +~~~~~~~~~~~~ + +- The use of WebOb's Response object to redirect a request to a new location + can lead to an open redirect if the Location header is not a full URI. + + See https://github.com/Pylons/webob/security/advisories/GHSA-mg3v-6m49-jhp3 + and CVE-2024-42353 + + Thanks to Sara Gao for the report + + (This fix was released in WebOb 1.8.8) + Feature ~~~~~~~ diff --git a/setup.py b/setup.py index 4186de41..cb7a988f 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,11 @@ "pytest-xdist", ] -docs_extras = ["Sphinx >= 1.7.5", "pylons-sphinx-themes"] +docs_extras = [ + "Sphinx >= 1.7.5", + "pylons-sphinx-themes", + "setuptools", +] setup( name="WebOb", diff --git a/src/webob/response.py b/src/webob/response.py index be4dbc60..5fffbfd5 100644 --- a/src/webob/response.py +++ b/src/webob/response.py @@ -1359,6 +1359,11 @@ def _make_location_absolute(environ, value): if SCHEME_RE.search(value): return value + # This is to fix an open redirect issue due to the way that + # urlparse.urljoin works. See CVE-2024-42353 and + # https://github.com/Pylons/webob/security/advisories/GHSA-mg3v-6m49-jhp3 + if value.startswith("//"): + value = f"/%2f{value[2:]}" new_location = urlparse.urljoin(_request_uri(environ), value) return new_location diff --git a/tests/test_response.py b/tests/test_response.py index f0b82085..f539b422 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -1085,6 +1085,17 @@ def test_location(): assert req.get_response(res).location == "http://localhost/test2.html" +def test_location_no_open_redirect(): + # This is a test for a fix for CVE-2024-42353 and + # https://github.com/Pylons/webob/security/advisories/GHSA-mg3v-6m49-jhp3 + res = Response() + res.status = "301" + res.location = "//www.example.com/test" + assert res.location == "//www.example.com/test" + req = Request.blank("/") + assert req.get_response(res).location == "http://localhost/%2fwww.example.com/test" + + @pytest.mark.xfail( sys.version_info < (3, 0), reason="Python 2.x unicode != str, WSGI requires str. Test "