RSTR-RDR-004 — Rails redirect_to params[:x]
Summary
A Rails controller calls redirect_to with a value taken directly
from params[...]. An attacker submits
?next=https://phish.example and the user sees a trusted-looking
link that lands on the attacker's page after the redirect.
This is the Rails counterpart of
RSTR-RDR-002 (Flask/Django) and
RSTR-RDR-003 (Go).
Recent Rails versions (5.0+) refuse cross-origin redirects by
default (ActionController::Redirecting::UnsafeRedirectError), but
same-origin phishing — /login?next=/admin/transfer?to=evil —
still succeeds. Always validate.
Severity
Medium.
Languages
Ruby (Rails).
What rastray flags
def callback
redirect_to params[:next] # ← flagged
end
redirect_to params[:url] # ← flagged
What rastray deliberately does not flag
Named route helpers and constant strings:
redirect_to dashboard_path # safe
redirect_to user_path(@user) # safe
redirect_to '/login' # safe
Indirect flow (path = params[:next]; redirect_to path) is also not
flagged — the same one-step taint scope used everywhere in rastray.
How to fix it
Allow-list the target. The simplest pattern uses a per-controller helper that returns either a sanitised path or a safe default:
class SessionsController < ApplicationController
def create
# ... authenticate ...
redirect_to safe_next_path
end
private
def safe_next_path
candidate = params[:next].to_s
return dashboard_path if candidate.blank?
# only allow same-origin, leading-slash, non-protocol-relative
uri = URI.parse(candidate) rescue nil
return dashboard_path unless uri && uri.host.nil? && candidate.start_with?('/')
return dashboard_path if candidate.start_with?('//')
candidate
end
end
For redirects to an external site, maintain an explicit allow-list of trusted hosts.