Read more

Do not pass all params into url_for

Arne Hartherz
September 13, 2023Software engineer at makandra GmbH

Rails' url_for is useful for generating routes from a Hash, but can lead to an open redirect vulnerability Show snapshot .

The problem

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show 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)

if expected_path != request.original_fullpath
  redirect_to expected_path

This works, but doing it like that you've just introduced 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.

What can I do?

  • Use request.path_parameters. That will exclude values like :host, :only_path, etc and is safe to generate paths inside your application. Note that it does not include query parameters.
  • Use redirect_to(url, allow_other_host: false) to avoid redirecting to foreign hosts. Careful: this only works for redirect_to. If you say e.g. link_to expected_path you'll still generate a link to a foreign host.
  • Use slice and/or exclude, like so: url_for(params.to_unsafe_h.exclude(:host, :protocol)). To feel extra safe, you can add merge(only_path: true) but excluding :host should have taken care of that.

Rails 7 mitigates Open Redirects by default

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.

Posted by Arne Hartherz to makandra dev (2023-09-13 15:27)