Skip to content

Commit 96c2926

Browse files
committed
Raise HTTPStatus::BadRequest for requests with invalid/duplicate content-length headers
Addresses CVE-2023-40225. Fixes #119
1 parent 649604e commit 96c2926

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

lib/webrick/httprequest.rb

+8
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,14 @@ def read_header(socket)
479479
end
480480
end
481481
@header = HTTPUtils::parse_header(@raw_header.join)
482+
483+
if (content_length = @header['content-length']) && content_length.length != 0
484+
if content_length.length > 1
485+
raise HTTPStatus::BadRequest, "multiple content-length request headers"
486+
elsif !/\A\d+\z/.match?(content_length[0])
487+
raise HTTPStatus::BadRequest, "invalid content-length request header"
488+
end
489+
end
482490
end
483491

484492
def parse_uri(str, scheme="http")

test/webrick/test_httprequest.rb

+25
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,31 @@ def test_request_uri_too_large
8181
}
8282
end
8383

84+
def test_invalid_content_length_header
85+
['', ' ', ' +1', ' -1', ' a'].each do |cl|
86+
msg = <<-_end_of_message_
87+
GET / HTTP/1.1
88+
Content-Length:#{cl}
89+
_end_of_message_
90+
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
91+
assert_raise(WEBrick::HTTPStatus::BadRequest){
92+
req.parse(StringIO.new(msg.gsub(/^ {8}/, "")))
93+
}
94+
end
95+
end
96+
97+
def test_duplicate_content_length_header
98+
msg = <<-_end_of_message_
99+
GET / HTTP/1.1
100+
Content-Length: 1
101+
Content-Length: 2
102+
_end_of_message_
103+
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
104+
assert_raise(WEBrick::HTTPStatus::BadRequest){
105+
req.parse(StringIO.new(msg.gsub(/^ {6}/, "")))
106+
}
107+
end
108+
84109
def test_parse_headers
85110
msg = <<-_end_of_message_
86111
GET /path HTTP/1.1

0 commit comments

Comments
 (0)