Rails SQL injection cheat sheet

The Rails module ActiveRecord provides good countermeasures against SQL injection (SQLi). But when using certain methods you’ll have to watch out. This site summarizes what not to do (in Rails 3.2.13, Rails 4.0.3, and SQLite 3, but most is valid in newer versions, too). Here’s the list in short:

  • Model.calculate(:sum, params[:column]), params[:column] may include arbitrary SQL
  • As a general rule, never use params in string inflection (#{}) like so:
    • User.delete_all("id = #{params[:id]}"),
    • User.destroy_all(["id = ? AND admin = '#{params[:admin]}", params[:id]]),
    • User.find(:first, :conditions => "name = '#{params[:name]}'"),
    • User.where("name = '#{params[:name]}'")
  • Watch out that params may also be an array, for example: params[:user] if you add ?user[]=1 to the URL. User.exists? params[:user] will then run the query SELECT 1 AS one FROM "users" WHERE (1) LIMIT 1.
  • Don’t use params in Model.find with the following options:
    • :order,
    • :group,
    • :having,
    • :joins,
    • :select,
    • :from,
    • :lock.
    • The same is true for the ARel methods with the same names, e.g. Model.order()
  • Don’t use params in Model.find_by like so: User.find_by params[:id]
  • Don’t use params in Model.pluck, for example Order.pluck(params[:column])
  • String inflection in Model.reorder leads to SQL injection: User.order("name DESC").reorder("id #{params[:order]}")
  • Model.update_all params[:order] leads to SQL Injection