CVE-2026-116578 — tornado
Fix: tornadoweb/tornado@940ea72CVE-2026-116578 is a Open Redirect vulnerability in tornado. A fix is available for tornado — see the affected versions and patch details below.
Tornado: Open redirect in RedirectHandler via protocol-relative URLs
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
tornadoReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
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/[email protected]/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).
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | tornado | all versions | 6.6pip install --upgrade 'tornado==6.6' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for tornado, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update tornado to 6.6 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-116578 is resolved across your whole dependency graph.
Workarounds
Stop reflecting attacker-controlled destinations: resolve every redirect target against an allowlist of paths or hosts you own, prefer a server-side key over a full URL in the request, and reject absolute URLs entirely where the flow only ever needs a relative one.
Frequently Asked Questions
Is CVE-2026-116578 in your dependencies?
Find it across PyPI, including transitive dependencies.