Rails' url_for
is
useful for generating routes from a Hash
Show archive.org snapshot
, but can lead to an
open redirect vulnerability
Show archive.org snapshot
.
Your application's
generated route methods with a _url
suffix
Show archive.org snapshot
are also affected because
they use url_for
unter the hood
Show archive.org snapshot
.
Imagine your application contains code that checks if the current request's path is what it would generate internally.
If different, it would redirect users to the generated/expected path.
expected_path = url_for(params.to_unsafe_h) # this is not safe!
if expected_path != request.original_fullpath
redirect_to expected_path
end
While this works in terms of fixing the expected path, it introduces an Open Redirect vulnerability.
It's as simple as passing a host=evil.tld
URL parameter. Rails would see url_for(..., host: "evil.tld")
and happily generate a URL to that foreign host.
This makes phishing much easier, because an attacker can use links with your application's hostname, cause a redirect to evil.tld
and present a sign-in form which looks like yours. Users will enter their login credentials and submit them to evil.tld
.
redirect_to(url, allow_other_host: false)
to avoid redirecting to foreign hosts. redirect_to
. For example, link_to(url)
will still generate a link to a foreign host and has no :allow_other_host
option.url_for
, use request.path_parameters
and request.query_parameters
as described below. url_for(params.permit(:foo, :bar))
.url_for(path_params: request.path_parameters, params: request.query_parameters)
url_for(**request.path_parameters, params: request.query_parameters)
Edge case for this approach: When a route contains path parameters like :host
(e.g. /foo/:host
), those will be part of request.path_parameters
and url_for(**request.path_parameters)
would then again generate a URL to a foreign host.
If your application defines such routes, you must mitigate the issue explicitly, or upgrade to Rails 7.1 and use its new :path_params
option.
We suggest you also add the following snippet which will raise a reminder message once you've upgraded to a newer Rails version.
if Gem::Version.new(Rails.version) >= Gem::Version.new("7.1")
raise "Replace **request.path_parameters with path_params: request.path_parameters"
end
In Rails 7 applications, redirect_to
defaults to allow_other_host: false
.
If you want to redirect to foreign hosts, you must specify allow_other_host: true
instead.
As mentioned above, this helps only with redirect_to
, not if you place such URLs in links or similar.