Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c364917

Browse files
authored
Merge pull request from GHSA-84j7-475p-hp8v
header value could inject a CR or LF and inject their own HTTP response.
1 parent 5f74663 commit c364917

8 files changed

Lines changed: 55 additions & 1 deletion

File tree

benchmarks/wrk/hello.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
bundle exec bin/puma -t 4 test/rackup/hello.ru &
44
PID1=$!
55
sleep 5
6-
wrk -c 4 --latency http://localhost:9292
6+
wrk -c 4 -d 30 --latency http://localhost:9292
77

88
kill $PID1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
bundle exec bin/puma -t 4 test/rackup/many_long_headers.ru &
2+
PID1=$!
3+
sleep 5
4+
wrk -c 4 -d 30 --latency http://localhost:9292
5+
6+
kill $PID1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
bundle exec bin/puma -t 4 test/rackup/realistic_response.ru &
2+
PID1=$!
3+
sleep 5
4+
wrk -c 4 -d 30 --latency http://localhost:9292
5+
6+
kill $PID1

lib/puma/const.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ module Const
228228
COLON = ": ".freeze
229229

230230
NEWLINE = "\n".freeze
231+
CRLF_REGEX = /[\r\n]/.freeze
231232

232233
HIJACK_P = "rack.hijack?".freeze
233234
HIJACK = "rack.hijack".freeze

lib/puma/server.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,8 @@ def handle_request(req, lines)
686686
status, headers, res_body = @app.call(env)
687687

688688
return :async if req.hijacked
689+
# Checking to see if an attacker is trying to inject headers into the response
690+
headers.reject! { |_k, v| CRLF_REGEX =~ v.to_s }
689691

690692
status = status.to_i
691693

test/rackup/many_long_headers.ru

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require 'securerandom'
2+
3+
long_header_hash = {}
4+
5+
30.times do |i|
6+
long_header_hash["X-My-Header-#{i}"] = SecureRandom.hex(1000)
7+
end
8+
9+
run lambda { |env| [200, long_header_hash, ["Hello World"]] }

test/rackup/realistic_response.ru

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require 'securerandom'
2+
3+
long_header_hash = {}
4+
5+
25.times do |i|
6+
long_header_hash["X-My-Header-#{i}"] = SecureRandom.hex(25)
7+
end
8+
9+
response = SecureRandom.hex(100_000) # A 100kb document
10+
11+
run lambda { |env| [200, long_header_hash.dup, [response.dup]] }

test/test_puma_server.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,4 +771,23 @@ def test_open_connection_wait_no_queue
771771
@server = Puma::Server.new @app, @events, queue_requests: false
772772
test_open_connection_wait
773773
end
774+
775+
# https://github.com/ruby/ruby/commit/d9d4a28f1cdd05a0e8dabb36d747d40bbcc30f16
776+
def test_prevent_response_splitting_headers
777+
server_run app: ->(_) { [200, {'X-header' => "malicious\r\nCookie: hack"}, ["Hello"]] }
778+
data = send_http_and_read "HEAD / HTTP/1.0\r\n\r\n"
779+
refute_match 'hack', data
780+
end
781+
782+
def test_prevent_response_splitting_headers_cr
783+
server_run app: ->(_) { [200, {'X-header' => "malicious\rCookie: hack"}, ["Hello"]] }
784+
data = send_http_and_read "HEAD / HTTP/1.0\r\n\r\n"
785+
refute_match 'hack', data
786+
end
787+
788+
def test_prevent_response_splitting_headers_lf
789+
server_run app: ->(_) { [200, {'X-header' => "malicious\nCookie: hack"}, ["Hello"]] }
790+
data = send_http_and_read "HEAD / HTTP/1.0\r\n\r\n"
791+
refute_match 'hack', data
792+
end
774793
end

0 commit comments

Comments
 (0)