diff --git a/docs/releases.rst b/docs/releases.rst index dd53b12ffed2d0d6896386bd4287548a49a7a05d..fc7e41654f4d00790aa08c93019579921ff34315 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -4,6 +4,7 @@ Release notes .. toctree:: :maxdepth: 2 + releases/v6.3.2 releases/v6.3.1 releases/v6.3.0 releases/v6.2.0 diff --git a/docs/releases/v6.3.2.rst b/docs/releases/v6.3.2.rst new file mode 100644 index 0000000000000000000000000000000000000000..250a6e4eb441ae91834a0f41b7a697c65e5e2563 --- /dev/null +++ b/docs/releases/v6.3.2.rst @@ -0,0 +1,11 @@ +What's new in Tornado 6.3.2 +=========================== + +May 13, 2023 +------------ + +Security improvements +~~~~~~~~~~~~~~~~~~~~~ + +- Fixed an open redirect vulnerability in StaticFileHandler under certain + configurations. \ No newline at end of file diff --git a/tornado/__init__.py b/tornado/__init__.py index afbd715053dbe9c24c99e765ec300de244a1bcc2..475c1f612eeac18a2a7c7d1460e52c8c73cc7979 100644 --- a/tornado/__init__.py +++ b/tornado/__init__.py @@ -22,8 +22,8 @@ # is zero for an official release, positive for a development branch, # or negative for a release candidate or beta (after the base version # number has been incremented) -version = "6.3.1" -version_info = (6, 3, 1, 0) +version = "6.3.2" +version_info = (6, 3, 2, 0) import importlib import typing diff --git a/tornado/web.py b/tornado/web.py index 3b676e3c2565e92eff491ee781807b3f42025ed4..565140493ef1f848b3cf1f38e694b047df45e38e 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -2879,6 +2879,15 @@ class StaticFileHandler(RequestHandler): # but there is some prefix to the path that was already # trimmed by the routing if not self.request.path.endswith("/"): + if self.request.path.startswith("//"): + # A redirect with two initial slashes is a "protocol-relative" URL. + # This means the next path segment is treated as a hostname instead + # of a part of the path, making this effectively an open redirect. + # Reject paths starting with two slashes to prevent this. + # This is only reachable under certain configurations. + raise HTTPError( + 403, "cannot redirect path with two initial slashes" + ) self.redirect(self.request.path + "/", permanent=True) return None absolute_path = os.path.join(absolute_path, self.default_filename)