CVE-2026-116578: Tornado: Open redirect in RedirectHandler via protocol-relative URLs
Summary
tornado.web.RedirectHandler builds its target URL by substituting parts of the request path into a template. Depending on where those substitutions appear in the template, an attacker can craft a request that redirects to a host of their choosing. This creates an open redirect on the application's domain, which can be used in phishing.
Impact
Applications are affected if they use RedirectHandler with a URL template where a regex capture group can influence the scheme or host of the redirect. This includes:
- A substitution at the start of the path, for example (r"/(.)/target", RedirectHandler, {"url": "/{0}/destination"}). A request to https://example.com//evil.com/target redirects to //evil.com/destination, a protocol-relative URL pointing to evil.com. Variants using backslashes or encoded characters have the same effect, because browsers treat them as equivalent to //. - A substitution directly after the host, for example (r"/old(.)", RedirectHandler, {"url": "https://new.example.com{0}"}). A request to /old.evil.com/ or /old@evil.com/ redirects to evil.com. - A template that begins with a substitution (such as "{0}"), which can be given an absolute URL.
Applications are not affected if their RedirectHandler templates use only static URLs, or if every substitution comes after a fixed host and a / (for example "/static/{0}" or "https://example.com/{0}"). Other uses of RequestHandler.redirect() are not affected by this advisory, although applications that pass user-controlled input to redirect() should validate it themselves.
Patches
Fixed in Tornado 6.6. RedirectHandler now returns a 400 error if the substituted values would change the scheme or host of the redirect from what the template specifies. As a result, substitutions can no longer be used in the scheme or host part of a template. The similar check in StaticFileHandler has also been hardened against backslash and whitespace variants.
Workarounds
- Change RedirectHandler templates so every substitution comes after a fixed prefix ending in /, or write capture-group regexes that cannot match characters such as /, \, @, . or : where they could affect the host. - Alternatively, replace RedirectHandler with a custom handler that validates the target before calling self.redirect().
Credit
Reported by Longwei Wang (@gn00295120).
Other sources
Tornado is a Python web framework and asynchronous networking library. Prior to 6.6, tornado.web.RedirectHandler URL templates can place regex-capture substitutions where crafted request paths change the redirect scheme or network location. Affected placements include substitutions at the start of a path, directly after a fixed host, or at the beginning of the template, including protocol-relative, absolute, backslash, encoded, host-extension, and user-info variants interpreted by browsers as attacker-controlled destinations. Static templates and substitutions after a fixed host followed by a slash are not affected. An attacker can use the resulting open redirect on the application's domain for phishing. This issue is fixed in version 6.6.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/tornadoto a version that resolves this vulnerability.Fixed in 6.6 - Upgrade
Upgrade
Tornadoto a version that resolves this vulnerability.Fixed in 6.6 - Configuration
Change RedirectHandler templates so every substitution follows a fixed prefix ending in '/', such as "/static/{0}" or "https://example.com/{0}"; alternatively use capture-group regexes that cannot match characters such as /, \, @, . or : where they could affect the host.
tornado.web.RedirectHandler URL templates = Substitutions only after a fixed prefix ending in /