rack 2.2.24 → 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 +12 -0
- data/lib/rack/multipart/parser.rb +26 -3
- data/lib/rack/static.rb +1 -1
- data/lib/rack/version.rb +1 -1
- metadata +1 -1
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,18 @@
|
|
|
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
|
+
|
|
5
17
|
## [2.2.24] - 2026-08-13
|
|
6
18
|
|
|
7
19
|
### Security
|
|
@@ -20,6 +20,9 @@ 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
|
|
|
@@ -93,7 +96,11 @@ module Rack
|
|
|
93
96
|
unless data[1].empty?
|
|
94
97
|
raise EOFError, "whitespace between boundary parameter name and equal sign"
|
|
95
98
|
end
|
|
96
|
-
|
|
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
|
|
97
104
|
raise EOFError, "multiple boundary parameters found in multipart content type"
|
|
98
105
|
end
|
|
99
106
|
|
|
@@ -346,6 +353,7 @@ module Rack
|
|
|
346
353
|
# buffering. Note that the actual limit is the higher of 64KB and the buffer size (1MB by default)
|
|
347
354
|
raise EOFError, "multipart mime part header too large" if @sbuf.rest.bytesize > MIME_HEADER_BYTESIZE_LIMIT
|
|
348
355
|
|
|
356
|
+
@sbuf.string = @sbuf.rest
|
|
349
357
|
return :want_read
|
|
350
358
|
end
|
|
351
359
|
end
|
|
@@ -366,8 +374,8 @@ module Rack
|
|
|
366
374
|
update_retained_size(body.bytesize) if @body_retained
|
|
367
375
|
@collector.on_mime_body @mime_index, body
|
|
368
376
|
@sbuf.pos += delta
|
|
369
|
-
@sbuf.string = @sbuf.rest
|
|
370
377
|
end
|
|
378
|
+
@sbuf.string = @sbuf.rest
|
|
371
379
|
:want_read
|
|
372
380
|
end
|
|
373
381
|
end
|
|
@@ -386,7 +394,7 @@ module Rack
|
|
|
386
394
|
# end of the boundary. If we don't find the start or end of the
|
|
387
395
|
# boundary, clear the buffer and return nil.
|
|
388
396
|
def consume_boundary
|
|
389
|
-
while read_buffer =
|
|
397
|
+
while read_buffer = scan_line
|
|
390
398
|
case read_buffer.strip
|
|
391
399
|
when full_boundary then return :BOUNDARY
|
|
392
400
|
when @end_boundary then return :END_BOUNDARY
|
|
@@ -395,6 +403,21 @@ module Rack
|
|
|
395
403
|
end
|
|
396
404
|
end
|
|
397
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
|
+
|
|
398
421
|
def get_filename(head)
|
|
399
422
|
filename = nil
|
|
400
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