Tornado: Open redirect in RedirectHandler via protocol-relative URLs
Impact
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.
Source excerpt · OSVAffected packages
Start with the recorded fix for your release branch. Check your installed version and test compatibility before upgrading. Fixing this advisory does not rule out other vulnerabilities in the release.
| Affected range | Recorded fix |
|---|---|
| Earlier releases before 6.6Ecosystem versions | 6.6 |
Version evidence: OSV · GHSA-pw9p-v7r6-gx4p
View original version evidence (89 explicit versions)
Affected products
Vendor version evidence. Product records are separate from automatic dependency matching.
tornadoweb · tornado
| Version / range | Source status |
|---|---|
| < 6.6 | affected |
Original source description
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 tohttps://example.com//evil.com/targetredirects 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
RedirectHandlertemplates 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
RedirectHandlerwith a custom handler that validates the target before callingself.redirect().
Credit
Reported by Longwei Wang (@gn00295120).
References
- Security advisory github.com/tornadoweb/tornado/security/advisories/GHSA-pw9p-v7r6-gx4p
- Patch github.com/tornadoweb/tornado/pull/3786
- Patch github.com/tornadoweb/tornado/commit/940ea725bdd9bc68231d68a105eef17ea6e11233
- Patch github.com/tornadoweb/tornado/commit/cc75ab0eb3af459c714895a49f682ad354f50117
- Patch github.com/tornadoweb/tornado/commit/ccb6a2e5482f17997efd4a74b8200d5b4babc035
- Release notes github.com/tornadoweb/tornado/releases/tag/v6.6.0
- Security advisory nvd.nist.gov/vuln/detail/CVE-2026-116578
- Source reference github.com/tornadoweb/tornado