Vulnerability
Rails

SQL Injection in Rails Applications

Rails' ActiveRecord ORM is generally safe when used with hash conditions and symbols. However, string-based where() conditions, find_by_sql(), order(), pluck(), and calculate() with string interpolation are common SQL injection vectors in Rails applications.

Scan Your Rails App

How SQL Injection Manifests in Rails

ActiveRecord provides safe query methods when used with hash syntax (where(name: value)), but string conditions with interpolation are vulnerable: - where("name = '#{params[:name]}'") - string interpolation in where clause - order(params[:sort]) - user-controlled ORDER BY - find_by_sql("SELECT * FROM users WHERE #{condition}") - raw SQL - pluck(params[:column]) - user-controlled column names Rails' Arel query builder can also be misused, and gems that build raw SQL (like pg_search) may introduce injection if not configured properly.

Real-World Impact

A Rails marketplace used string interpolation in a where() clause for searching products. An attacker discovered the endpoint accepted SQL in the search parameter and used a time-based blind SQL injection to extract the secret_key_base from the database, which allowed them to forge session cookies and impersonate any user.

Step-by-Step Fix

1

Use safe ActiveRecord query patterns

Replace string interpolation with hash or array conditions.

# UNSAFE - string interpolation
User.where("email = '#{params[:email]}'")
User.where("name LIKE '%#{params[:q]}%'")

# SAFE - hash conditions
User.where(email: params[:email])

# SAFE - array conditions (parameterized)
User.where("name LIKE ?", "%#{params[:q]}%")
User.where("created_at > ? AND role = ?", params[:since], params[:role])
2

Allowlist order() parameters

Never pass user input directly to order().

ALLOWED_SORTS = {
  'newest' => 'created_at DESC',
  'oldest' => 'created_at ASC',
  'name' => 'name ASC',
  'price_low' => 'price ASC',
  'price_high' => 'price DESC',
}.freeze

def index
  sort = ALLOWED_SORTS[params[:sort]] || 'created_at DESC'
  @products = Product.order(Arel.sql(sort)).page(params[:page])
end
3

Secure find_by_sql

Use parameterized queries with find_by_sql.

# UNSAFE
User.find_by_sql("SELECT * FROM users WHERE status = '#{status}'")

# SAFE - parameterized
User.find_by_sql(["SELECT * FROM users WHERE status = ?", status])
4

Run Brakeman for automated scanning

Brakeman detects SQL injection and other vulnerabilities in Rails apps.

# Install and run
gem install brakeman
brakeman --path /your/rails/app

# In Gemfile for CI integration
group :development do
  gem 'brakeman', require: false
end

Prevention Best Practices

1. Always use hash conditions in where(): where(name: value) instead of where("name = '#{value}'"). 2. Use array conditions for complex queries: where("name LIKE ?", "%#{search}%"). 3. Validate and allowlist ORDER BY columns and directions. 4. Never use string interpolation in find_by_sql, where, or order. 5. Use Brakeman for automated Rails security scanning.

How to Test

1. Search for string interpolation in queries: grep -rn "where(".*#\{" --include="*.rb" 2. Check for order(params[...]) and pluck(params[...]) patterns. 3. Test with ' OR 1=1 -- in search fields and filter parameters. 4. Run Brakeman: brakeman --path . to detect SQL injection automatically. 5. Use Vibe App Scanner to detect SQL injection in your Rails application.

Frequently Asked Questions

Is ActiveRecord safe from SQL injection?

ActiveRecord is safe when using hash conditions (where(name: value)) and array conditions (where("name = ?", value)). String conditions with interpolation (where("name = '#{value}'")) are vulnerable. The ORM protects you only when you use its safe API.

What is Brakeman and should I use it?

Brakeman is a static analysis tool specifically designed for Rails security. It detects SQL injection, XSS, and other vulnerabilities by analyzing your Ruby code. It should be part of every Rails project's CI pipeline.

Can I use Arel.sql() safely?

Arel.sql() marks a string as safe SQL, bypassing ActiveRecord's protection. Only use it with hardcoded strings or values from an allowlist. Never use it with user input. It is commonly needed for ORDER BY clauses with validated values.

Is Your Rails App Vulnerable to SQL Injection?

VAS automatically scans for sql injection vulnerabilities in Rails applications and provides step-by-step remediation guidance with code examples.

Scans from $5, results in minutes. Get actionable fixes tailored to your Rails stack.