Rails ships with more security protections on by default than most frameworks - CSRF protection, strong parameters, and auto-escaped ERB templates all require no setup. The real-world Rails vulnerabilities that actually happen are almost always an explicit, deliberate override of one of these defaults, made to solve an integration problem and never revisited.
1. Protect master.key and credentials.yml.enc
config/master.key decrypts config/credentials.yml.enc, which typically holds every application secret - database credentials, API keys, secret_key_base. The encrypted credentials file is meant to be committed; the master key is explicitly gitignored by Rails' own default .gitignore - confirm it stays that way rather than getting force-added by someone unfamiliar with which file is which.
2. Strong Parameters: Watch for permit!
# Vulnerable: permits every attribute with no allowlist at all
def user_params
params.require(:user).permit!
end
# Fixed: explicit allowlist
def user_params
params.require(:user).permit(:name, :bio)
end
permit! exists for genuine edge cases (trusted internal admin tools processing a large, evolving set of fields) and is a real mass-assignment vulnerability everywhere else - grep for it across a Rails codebase the same way you'd grep a React codebase for dangerouslySetInnerHTML.
3. CSRF: Check skip_before_action
# Worth auditing every occurrence of this in a real codebase
skip_before_action :verify_authenticity_token, only: [:webhook]
# Legitimate for a webhook endpoint with its own signature verification.
# Not legitimate as a quick fix for an API client that "isn't sending the token" -
# the actual fix there is switching that controller to token-based auth.
4. SQL Injection via Manual Interpolation
# Vulnerable
User.where("email = '#{params[:email]}'")
# Fixed: ActiveRecord parameterizes standard where() calls automatically
User.where(email: params[:email])
User.where("email = ?", params[:email])
5. Session Store and Cookie Security
# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store,
secure: Rails.env.production?,
same_site: :strict
Rails' default cookie-based session store encrypts and signs the cookie, so its contents aren't readable or forgeable without the app's secret - but the Secure and SameSite transport flags above still need to be set explicitly for HTTPS-only transmission and CSRF-resistant cookie behavior.
6. CORS (rack-cors)
Rails has no CORS support by default for API-only applications - the rack-cors gem is the standard addition, and the same wildcard-origin-plus-credentials combination that's dangerous in every other framework applies here too.
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://yourapp.com'
resource '*', headers: :any, methods: [:get, :post], credentials: true
end
end
7. Content Security Policy
Rails 6+ includes a CSP DSL (config/initializers/content_security_policy.rb) but it's opt-in and unconfigured by default - unlike CSRF and mass-assignment protection, this is a genuine "you need to add it yourself" gap, not a default being overridden.
8. Dependency Scanning
bundle exec bundler-audit check --update
Run in CI on every build - Rails and its ecosystem gems have had real, high-severity CVEs (several in Rails' own XML/YAML parsing over the years), and a Gemfile.lock pinned to an old version doesn't announce that it's become vulnerable on its own.
9. Rate Limiting (rack-attack)
# config/initializers/rack_attack.rb
Rack::Attack.throttle('logins/ip', limit: 5, period: 60) do |req|
req.ip if req.path == '/login' && req.post?
end
10. Debug Mode / Detailed Errors in Production
config.consider_all_requests_local and config.action_dispatch.show_exceptions control whether a Rails app shows the full interactive error page - Rails' production environment defaults to hiding these, but a copy-pasted development config override can reintroduce full stack trace exposure.
Verifying From the Outside
Try Shieldome's Ruby on Rails security scanner to check headers, exposed configuration, and cookie security from the outside. Create a free account to run your first scan.