-
Notifications
You must be signed in to change notification settings - Fork 828
Rails 8 Changes From Rails 5
This guide provides a comprehensive comparison of security features and vulnerabilities between Rails 5 (what RailsGoat was originally built for) and Rails 8 (the current version).
93% of RailsGoat vulnerabilities still apply to Rails 8 because most web security issues are caused by developer mistakes, not framework flaws. Rails 8 makes it easier to be secure with better defaults and tools, but the same vulnerabilities exist when developers:
- Disable built-in protections
- Use unsafe methods
- Write custom authentication logic
- Don't validate user input
- Expose sensitive data through APIs
The Big One: Rails 8 sets Regexp.timeout = 1.0 by default.
# Rails 5 - This can hang forever
username =~ /^(a+)+$/
# Rails 8 - Raises Regexp::TimeoutError after 1 second
username =~ /^(a+)+$/Impact: Prevents Regular Expression Denial of Service attacks automatically.
Learn More: A1 - ReDoS Tutorial
What's New: bin/rails generate authentication creates secure auth out-of-the-box.
# Rails 8
rails generate authentication
# Generates:
# - User model with has_secure_password
# - Sessions controller with authenticate_by
# - Password reset functionality
# - BCrypt password hashingRails 5 Equivalent: Manual implementation required (prone to mistakes).
RailsGoat Context: The credential enumeration vulnerability (A2) only exists because developers write custom authentication like RailsGoat does. Rails 8 makes it easier to avoid these mistakes.
Learn More: R8 - Authentication Improvements
What's New: Stricter parameter filtering than params.permit().
# Rails 5 - params.permit()
def user_params
params.require(:user).permit(:email, :first_name, :last_name)
end
# Rails 8 - params.expect() (more explicit)
def user_params
params.expect(user: [:email, :first_name, :last_name])
endBenefits:
- More explicit about what parameters are expected
- Better error messages when structure doesn't match
- Can help prevent mass assignment vulnerabilities
RailsGoat Context: Doesn't fix the fundamental mass assignment issue if developers permit admin attributes, but makes intent clearer.
Learn More: R8 - Parameter Handling
What's New: Better CSP configuration and defaults.
# config/initializers/content_security_policy.rb (Rails 8)
Rails.application.config.content_security_policy do |policy|
policy.default_src :self, :https
policy.script_src :self, :https
policy.style_src :self, :https
# ... more defaults
endImpact on XSS: Properly configured CSP provides defense-in-depth against XSS attacks.
RailsGoat Context: XSS vulnerabilities from .html_safe still exist, but CSP can limit damage.
Rails 5 Vulnerable Pattern:
User.where("id = '#{params[:user][:id]}'") # String interpolationRails 8: Same vulnerability if developers use string interpolation.
Current Status in RailsGoat: Still vulnerable at app/controllers/users_controller.rb:29
Why It Persists: Framework can't prevent string interpolation in queries.
Mitigation (Same in Both):
User.where("id = ?", params[:user][:id]) # Parameterized query
User.find(params[:user][:id]) # Idiomatic RailsRails 5 Vulnerable Pattern:
system("cp #{file.original_filename} #{backup_path}")Rails 8: Same vulnerability if developers use system() with user input.
Why It Persists: Framework can't prevent unsafe system calls.
Mitigation (Same in Both):
FileUtils.cp(file.original_filename, backup_path) # Use Ruby methodsRails 5 Vulnerable Pattern:
user = find_by_email(email)
raise "#{email} doesn't exist!" if !user # Reveals email exists
raise "Incorrect Password!" if wrong_password # Different errorRails 8: Same vulnerability if developers write custom authentication with specific error messages.
Why It Persists: Framework can't enforce generic error messages in custom code.
Rails 8 Improvement: New auth generator uses generic messages by default, but RailsGoat uses custom auth.
Rails 5 Vulnerable Pattern:
config.session_store :cookie_store, key: "_railsgoat_session", httponly: falseRails 8: Same vulnerability when explicitly disabled.
Current Status in RailsGoat: Still set to false in config/initializers/session_store.rb:4
Why It Persists: Developers can still disable security features.
Default Behavior: Both Rails 5 and 8 enable HttpOnly by default - RailsGoat explicitly disables it.
Rails 5 Vulnerable Pattern:
<%= current_user.first_name.html_safe %> # Bypasses escapingRails 8: Same vulnerability when .html_safe or raw is used.
Why It Persists: Developers need a way to render HTML; misuse creates XSS.
Rails 8 Improvement: Better CSP support provides defense-in-depth, but doesn't fix the root cause.
Rails 5 Vulnerable Pattern:
@user = User.find_by(id: params[:user_id]) # Uses URL paramRails 8: Same vulnerability when using URL parameters instead of session.
Why It Persists: Framework can't enforce session-based access control.
Rails 8 Note: params.expect() makes parameter access more explicit but doesn't prevent IDOR.
Mitigation (Same in Both):
@user = current_user # Use session-based user objectRails 5 Vulnerable Pattern:
respond_with @user # Returns all attributes including passwordRails 8: Same vulnerability when not overriding serialization.
Why It Persists: Default JSON serialization includes all attributes.
Mitigation (Same in Both):
# Override as_json
def as_json(options = {})
super(only: [:id, :email, :first_name, :last_name])
endRails 5 Vulnerable Pattern:
self.password = Digest::MD5.hexdigest(password) # MD5, no saltRails 8: Same vulnerability if developers use MD5 or weak hashing.
Why It Persists: Framework can't prevent developers from using weak crypto.
Rails 8 Improvement: Auth generator uses has_secure_password (BCrypt) by default.
Mitigation (Same in Both):
class User < ApplicationRecord
has_secure_password # Built-in BCrypt support
endRails 5 Vulnerable Pattern:
# SSN stored in plain text in database
create_table :work_infos do |t|
t.string :SSN # Plain text
endRails 8: Same vulnerability without explicit encryption.
Why It Persists: ActiveRecord doesn't automatically encrypt attributes.
Rails 8 Option: Can use encrypts :ssn (available since Rails 7), but must be explicitly added.
Rails 5 Vulnerable Pattern:
before_filter :administrative, if: :admin_param
def admin_param
params[:id] != '1' # Bypass if ID is 1
endRails 8: Same vulnerability when using attacker-controlled conditions.
Why It Persists: Framework can't prevent logic errors in authorization.
Note: Rails 5 used before_filter; Rails 8 uses before_action (deprecated in Rails 5, removed in Rails 8).
Rails 5 Vulnerable Pattern:
#protect_from_forgery with: :exception # COMMENTED OUTRails 8: Same vulnerability when protection is disabled.
Current Status in RailsGoat: Still commented out in app/controllers/application_controller.rb:9
Why It Persists: Developers can still disable CSRF protection.
Default Behavior: Both Rails 5 and 8 enable CSRF protection by default - RailsGoat explicitly disables it.
Rails 5 Vulnerable Pattern:
// Third-party library with XSS vulnerability
top.consoleRef.document.writeln('<title>'+location.href+'</title>');Rails 8: Same vulnerability when using vulnerable dependencies.
Why It Persists: Third-party code can have vulnerabilities.
Rails 8 Note: Importmaps may reduce JavaScript dependency surface, but vulnerabilities still possible.
Rails 5 Vulnerable Pattern:
path = params[:url] # No validation
redirect_to path # Redirects anywhereRails 8: Same vulnerability without URL validation.
Why It Persists: Framework can't automatically determine which redirects are safe.
Mitigation (Same in Both):
def safe_redirect_path(path, default: root_path)
Rails.application.routes.recognize_path(path)
path
rescue ActionController::RoutingError
default
end| Category | Rails 5 Status | Rails 8 Status | Framework Fix? | Notes |
|---|---|---|---|---|
| A1 - SQL Injection | β Vulnerable | β Vulnerable | No | String interpolation still possible |
| A1 - Command Injection | β Vulnerable | β Vulnerable | No | system() still accepts user input |
| A1 - ReDoS | β Vulnerable | β Protected | Yes | Automatic 1s timeout |
| A2 - Credential Enum | β Vulnerable | β Vulnerable | No | Custom auth still possible |
| A2 - HttpOnly Disabled | β Vulnerable | β Vulnerable | No | Can still be disabled |
| A2 - Weak Passwords | β Vulnerable | π§ Easier | Partial | Auth generator uses BCrypt |
| A3 - XSS (.html_safe) | β Vulnerable | β Vulnerable | No | Method still available |
| A3 - DOM XSS | β Vulnerable | β Vulnerable | No | Client-side issue |
| A4 - IDOR | β Vulnerable | β Vulnerable | No | Params vs session choice |
| A6 - API Data Exposure | β Vulnerable | β Vulnerable | No | Default serialization |
| A6 - MD5 Hashing | β Vulnerable | π§ Easier | Partial | has_secure_password easier |
| A6 - Cleartext Storage | β Vulnerable | π§ Easier | Partial |
encrypts available (Rails 7+) |
| A7 - Missing AuthZ | β Vulnerable | β Vulnerable | No | Logic errors possible |
| A8 - CSRF Disabled | β Vulnerable | β Vulnerable | No | Can still be disabled |
| A9 - Vuln Dependencies | β Vulnerable | β Vulnerable | No | Third-party code |
| A10 - Open Redirects | β Vulnerable | β Vulnerable | No | No auto URL validation |
Legend:
- β Vulnerable: Same vulnerability exists
- β Protected: Framework prevents vulnerability
- π§ Easier: Framework makes secure implementation easier, but not required
Rails can't prevent:
- String interpolation in SQL queries
- Using
system()with user input - Calling
.html_safeon user data - Writing authorization logic with security holes
- Disabling built-in protections
But developers can still:
- Comment out
protect_from_forgery - Set
httponly: false - Use MD5 instead of BCrypt
- Write custom authentication with flaws
Because it demonstrates how developers introduce vulnerabilities by:
- Misusing framework features
- Disabling security protections
- Writing unsafe custom code
- Not following best practices
ReDoS protection is the only vulnerability where Rails 8 provides automatic protection that developers can't easily bypass (without explicitly setting Regexp.timeout = nil).
Rails 8 is a security improvement, but not a silver bullet. The framework provides better defaults and tools, but the vast majority of web application vulnerabilities stem from developer mistakes rather than framework issues. This means RailsGoat remains highly relevant for Rails 8 security training, with the added benefit of demonstrating new Rails 8-specific protections like ReDoS prevention.
Sections are divided by their OWASP Top Ten label (A1-A10) and marked as R4 and R5 for Rails 4 and 5.