rack 2.2.23 → 2.2.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/lib/rack/multipart/parser.rb +37 -7
- data/lib/rack/static.rb +1 -1
- data/lib/rack/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c5322ca41af487959f08981c9964d7ef877f82b0ee4374e4338bedbeb93d3538
|
|
4
|
+
data.tar.gz: 4accf7c52defac80efd55caef60ef967f1a813743d8487723e733f66591fce5d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4b5cedb21343a2e062ca5daf8c55f88fe29bc7d884244dcd13ca6cad858e61764b18f71ea93cfb6a538bc03dadbb82ad7471895d1f6cbc1b2bc727651a807a11
|
|
7
|
+
data.tar.gz: 5bc5a948d20e77d1c831173b4ba5ba5b661bc985f60a6bf9fd1224033c6725ed2c8753f39766a3fe386b56457de9439ace3459cd0f1f650dd0c7fdb2effdcc13
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. For info on how to format all future additions to this file please reference [Keep A Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
4
4
|
|
|
5
|
+
## [2.2.25] - 2026-10-30
|
|
6
|
+
|
|
7
|
+
### Security
|
|
8
|
+
|
|
9
|
+
- [GHSA-5v64-555j-wjxm](https://github.com/advisories/GHSA-5v64-555j-wjxm) Multipart parser retains parsed data in its scan buffer, allowing denial of service via memory exhaustion.
|
|
10
|
+
- [GHSA-wvg4-6p58-3gh3](https://github.com/advisories/GHSA-wvg4-6p58-3gh3) `Rack::Static` header rules were matched against an unnormalized path, allowing dot segments to bypass them.
|
|
11
|
+
- [GHSA-p8x9-v4hv-2w4g](https://github.com/advisories/GHSA-p8x9-v4hv-2w4g) Multipart requests with more than one `boundary` parameter were accepted when the first value was empty or began with a quote, semicolon, or comma, bypassing the guard added for CVE-2026-26961.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Multipart parser: scan boundary lines with a literal newline search instead of a backtracking regexp, which allocated tens of megabytes per scan for long lines and made the scan buffer fix above ineffective on this series.
|
|
16
|
+
|
|
17
|
+
## [2.2.24] - 2026-08-13
|
|
18
|
+
|
|
19
|
+
### Security
|
|
20
|
+
|
|
21
|
+
- [CVE-2026-26962](https://github.com/advisories/GHSA-rx22-g9mx-qrhv) Improper unfolding of folded multipart headers preserves CRLF in parsed parameter values.
|
|
22
|
+
|
|
5
23
|
## [2.2.23] - 2026-04-01
|
|
6
24
|
|
|
7
25
|
### Security
|
|
@@ -20,10 +20,17 @@ module Rack
|
|
|
20
20
|
|
|
21
21
|
BOUNDARY_REGEX = /\A([^\n]*(?:\n|\Z))/
|
|
22
22
|
|
|
23
|
+
LINE_END = /\n/
|
|
24
|
+
private_constant :LINE_END
|
|
25
|
+
|
|
23
26
|
BOUNDARY_START_LIMIT = 16 * 1024
|
|
24
27
|
private_constant :BOUNDARY_START_LIMIT
|
|
25
28
|
|
|
26
29
|
MIME_HEADER_BYTESIZE_LIMIT = 64 * 1024
|
|
30
|
+
|
|
31
|
+
OBS_UNFOLD = /\r\n([ \t])/
|
|
32
|
+
|
|
33
|
+
private_constant :OBS_UNFOLD
|
|
27
34
|
private_constant :MIME_HEADER_BYTESIZE_LIMIT
|
|
28
35
|
|
|
29
36
|
env_int = lambda do |key, val|
|
|
@@ -89,7 +96,11 @@ module Rack
|
|
|
89
96
|
unless data[1].empty?
|
|
90
97
|
raise EOFError, "whitespace between boundary parameter name and equal sign"
|
|
91
98
|
end
|
|
92
|
-
|
|
99
|
+
# Count across the whole header rather than only after the match: the
|
|
100
|
+
# lazy prefix in MULTIPART can skip a first boundary parameter whose
|
|
101
|
+
# value is empty or starts with a quote, semicolon, or comma. Also
|
|
102
|
+
# count RFC 2231 boundary* parameters, which some parsers prefer.
|
|
103
|
+
if content_type.scan(/boundary(?:\*\d*\*?)?\s*=/i).size > 1
|
|
93
104
|
raise EOFError, "multiple boundary parameters found in multipart content type"
|
|
94
105
|
end
|
|
95
106
|
|
|
@@ -310,14 +321,17 @@ module Rack
|
|
|
310
321
|
def handle_mime_head
|
|
311
322
|
if @sbuf.scan_until(@head_regex)
|
|
312
323
|
head = @sbuf[1]
|
|
313
|
-
|
|
314
|
-
|
|
324
|
+
# Implement OBS unfolding (RFC 5322 Section 2.2.3). Done on a copy
|
|
325
|
+
# because content type, disposition and filename are extracted by regex.
|
|
326
|
+
unfolded_head = head.gsub(OBS_UNFOLD, '\\1')
|
|
327
|
+
content_type = unfolded_head[MULTIPART_CONTENT_TYPE, 1]
|
|
328
|
+
if name = unfolded_head[MULTIPART_CONTENT_DISPOSITION, 1]
|
|
315
329
|
name = Rack::Auth::Digest::Params::dequote(name)
|
|
316
330
|
else
|
|
317
|
-
name =
|
|
331
|
+
name = unfolded_head[MULTIPART_CONTENT_ID, 1]
|
|
318
332
|
end
|
|
319
333
|
|
|
320
|
-
filename = get_filename(
|
|
334
|
+
filename = get_filename(unfolded_head)
|
|
321
335
|
|
|
322
336
|
if name.nil? || name.empty?
|
|
323
337
|
name = filename || "#{content_type || TEXT_PLAIN}[]".dup
|
|
@@ -339,6 +353,7 @@ module Rack
|
|
|
339
353
|
# buffering. Note that the actual limit is the higher of 64KB and the buffer size (1MB by default)
|
|
340
354
|
raise EOFError, "multipart mime part header too large" if @sbuf.rest.bytesize > MIME_HEADER_BYTESIZE_LIMIT
|
|
341
355
|
|
|
356
|
+
@sbuf.string = @sbuf.rest
|
|
342
357
|
return :want_read
|
|
343
358
|
end
|
|
344
359
|
end
|
|
@@ -359,8 +374,8 @@ module Rack
|
|
|
359
374
|
update_retained_size(body.bytesize) if @body_retained
|
|
360
375
|
@collector.on_mime_body @mime_index, body
|
|
361
376
|
@sbuf.pos += delta
|
|
362
|
-
@sbuf.string = @sbuf.rest
|
|
363
377
|
end
|
|
378
|
+
@sbuf.string = @sbuf.rest
|
|
364
379
|
:want_read
|
|
365
380
|
end
|
|
366
381
|
end
|
|
@@ -379,7 +394,7 @@ module Rack
|
|
|
379
394
|
# end of the boundary. If we don't find the start or end of the
|
|
380
395
|
# boundary, clear the buffer and return nil.
|
|
381
396
|
def consume_boundary
|
|
382
|
-
while read_buffer =
|
|
397
|
+
while read_buffer = scan_line
|
|
383
398
|
case read_buffer.strip
|
|
384
399
|
when full_boundary then return :BOUNDARY
|
|
385
400
|
when @end_boundary then return :END_BOUNDARY
|
|
@@ -388,6 +403,21 @@ module Rack
|
|
|
388
403
|
end
|
|
389
404
|
end
|
|
390
405
|
|
|
406
|
+
# Return the next line of the buffer including its trailing "\n", or the
|
|
407
|
+
# rest of the buffer if it contains no "\n", and advance past it. This is
|
|
408
|
+
# equivalent to `@sbuf.scan_until(BOUNDARY_REGEX)`, but searching for the
|
|
409
|
+
# "\n" directly avoids the regexp engine's backtracking stack, which grows
|
|
410
|
+
# by one entry per byte matched by `[^\n]*` (tens of MB for a 1 MB line).
|
|
411
|
+
def scan_line
|
|
412
|
+
if line = @sbuf.scan_until(LINE_END)
|
|
413
|
+
line
|
|
414
|
+
else
|
|
415
|
+
line = @sbuf.rest
|
|
416
|
+
@sbuf.terminate
|
|
417
|
+
line
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
391
421
|
def get_filename(head)
|
|
392
422
|
filename = nil
|
|
393
423
|
case head
|
data/lib/rack/static.rb
CHANGED
|
@@ -168,7 +168,7 @@ module Rack
|
|
|
168
168
|
|
|
169
169
|
# Convert HTTP header rules to HTTP headers
|
|
170
170
|
def applicable_rules(path)
|
|
171
|
-
path = ::Rack::Utils.unescape_path(path)
|
|
171
|
+
path = ::Rack::Utils.clean_path_info(::Rack::Utils.unescape_path(path))
|
|
172
172
|
|
|
173
173
|
@header_rules.find_all do |rule, new_headers|
|
|
174
174
|
case rule
|
data/lib/rack/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.2.
|
|
4
|
+
version: 2.2.25
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leah Neukirchen
|
|
@@ -182,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
182
182
|
- !ruby/object:Gem::Version
|
|
183
183
|
version: '0'
|
|
184
184
|
requirements: []
|
|
185
|
-
rubygems_version: 4.0.
|
|
185
|
+
rubygems_version: 4.0.10
|
|
186
186
|
specification_version: 4
|
|
187
187
|
summary: A modular Ruby webserver interface.
|
|
188
188
|
test_files: []
|