RSTR-INJ-009 — Rails params[:x].constantize / .classify / .safe_constantize
Summary
A Rails handler resolves a class by calling .constantize,
.safe_constantize, or .classify on a request parameter. An attacker
who controls the string can instantiate any class in the autoload
namespace — including ones whose initialize / _load / inherited
hooks have dangerous side effects. The "mobile API" pattern of
"deserialize whatever class the client names" historically led to RCE
via gadget chains in several published Rails advisories.
Severity
High.
Languages
Ruby (Rails).
What rastray flags
model = params[:class].constantize # ← flagged
klass = params[:kind].safe_constantize # ← flagged
model = params[:type].classify # ← flagged
What rastray deliberately does not flag
Allow-list resolution:
ALLOWED = { 'user' => User, 'admin' => AdminUser, 'guest' => GuestUser }
klass = ALLOWED.fetch(params[:kind]) { raise ActionController::BadRequest }
klass = case params[:kind]
when 'user' then User
when 'admin' then AdminUser
end
.constantize on a constant or a non-params source is also not
flagged.
How to fix it
Resolve through an allow-list. The hash-with-fetch idiom above is the canonical pattern; the case-statement form is equally fine. Both ensure only classes the developer intended are reachable.
If the parameter is supposed to be one of a small fixed set, just do an explicit comparison rather than reflection:
if %w[user admin guest].include?(params[:kind])
# safe to use params[:kind] in a query, but still construct
# the class explicitly elsewhere
end