rack 3.1.21 → 3.1.23

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7aaf1007eae50de14eec6eaa6a4d586f1fe15b614bfe77bf68bea65c6ad59423
4
- data.tar.gz: 56ce4db8b9c1aeffaf750836ea16bf264841909aeb4befb81719e45189742ac3
3
+ metadata.gz: 0eea0a8704e9041b0816ff683feadf99a2f94106884de54455550b427f437981
4
+ data.tar.gz: 72e7f3f74af13b783cb4ad583301092c0ccb19b8245a72fe9c1ed38351c8067f
5
5
  SHA512:
6
- metadata.gz: 3917f67c856cf670e2f3eaf4432b74366f8b5ee09a78ae2acad9075b10cca355fc718b5025fed92091b56187e4e614fc5ab24066c26298a3af4352ec064fe490
7
- data.tar.gz: 6a741930a02797a64a50bf7fb8e11957e4bf0c5771a26e0491c131c3ad71d0e120f5a70ceec80fe12c0d866daaa822eb0cdcb9f55a9a2d509ef01659fde08231
6
+ metadata.gz: fd22ed0b602803fce4cc4a4b00e3e055f5dafc7b9ef8925d4c2d9fb7eed1c5ee27eec1a06001b08dd560e62074dd9a6f7dffcc70b1229eebae81648be8914f9f
7
+ data.tar.gz: 4563c28eaa11ff0a607c8f1d31a8b9483fd1d9b0b9ca55d684bea8bf52e50d72519ec062d130921108b115537e6738792645307718f20c7ec8b9a8e563166811
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
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
+ ## [3.1.23] - 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-2j8w-xcrc-x985](https://github.com/advisories/GHSA-2j8w-xcrc-x985) `Rack::Request#host_with_port`, `#base_url`, and `#url` returned the raw authority when it was invalid; `host_with_port` now returns `nil` in that case.
12
+ - [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.
13
+
14
+ ## [3.1.22] - 2026-08-13
15
+
16
+ ### Security
17
+
18
+ - [CVE-2026-26962](https://github.com/advisories/GHSA-rx22-g9mx-qrhv) Improper unfolding of folded multipart headers preserves CRLF in parsed parameter values.
19
+
20
+ ### Fixed
21
+
22
+ - Restore Ruby 2.4/2.5 compatibility.
23
+
5
24
  ## [3.1.21] - 2026-04-01
6
25
 
7
26
  ### Security
@@ -17,7 +36,7 @@ All notable changes to this project will be documented in this file. For info on
17
36
  - [CVE-2026-34830](https://github.com/advisories/GHSA-qv7j-4883-hwh7) `Rack::Sendfile` header-based `X-Accel-Mapping` regex injection enables unauthorized `X-Accel-Redirect`.
18
37
  - [CVE-2026-34785](https://github.com/advisories/GHSA-h2jq-g4cq-5ppq) `Rack::Static` prefix matching can expose unintended files under the static root.
19
38
  - [CVE-2026-34829](https://github.com/advisories/GHSA-8vqr-qjwx-82mw) Multipart parsing without `Content-Length` header allows unbounded chunked file uploads.
20
- - [CVE-2026-34827](https://github.com/advisories/GHSA-v6x5-cg8r-vv6x) Quadratic-time multipart header parsing allows denial of service via escape-heavy quoted parameters.
39
+ - [CVE-2026-34827](https://github.com/advisories/GHSA-v6x5-cg8r-vv6x) Multipart header parsing allows denial of service via escape-heavy quoted parameters.
21
40
 
22
41
  ## [3.1.20] - 2026-02-16
23
42
 
@@ -410,6 +429,26 @@ Rack v3.1 is primarily a maintenance release that removes features deprecated in
410
429
  - Fix multipart filename generation for filenames that contain spaces. Encode spaces as "%20" instead of "+" which will be decoded properly by the multipart parser. ([#1736](https://github.com/rack/rack/pull/1645), [@muirdm](https://github.com/muirdm))
411
430
  - `Rack::Request#scheme` returns `ws` or `wss` when one of the `X-Forwarded-Scheme` / `X-Forwarded-Proto` headers is set to `ws` or `wss`, respectively. ([#1730](https://github.com/rack/rack/issues/1730), [@erwanst](https://github.com/erwanst))
412
431
 
432
+ ## [2.2.24] - 2026-08-13
433
+
434
+ ### Security
435
+
436
+ - [CVE-2026-26962](https://github.com/advisories/GHSA-rx22-g9mx-qrhv) Improper unfolding of folded multipart headers preserves CRLF in parsed parameter values.
437
+
438
+ ## [2.2.23] - 2026-04-01
439
+
440
+ ### Security
441
+
442
+ - [CVE-2026-34763](https://github.com/advisories/GHSA-7mqq-6cf9-v2qp) Root directory disclosure via unescaped regex interpolation in `Rack::Directory`.
443
+ - [CVE-2026-34230](https://github.com/advisories/GHSA-v569-hp3g-36wr) Avoid O(n^2) algorithm in `Rack::Utils.select_best_encoding` which could lead to denial of service.
444
+ - [CVE-2026-26961](https://github.com/advisories/GHSA-vgpv-f759-9wx3) Raise error for multipart requests with multiple boundary parameters.
445
+ - [CVE-2026-34786](https://github.com/advisories/GHSA-q4qf-9j86-f5mh) `Rack::Static` `header_rules` bypass via URL-encoded path mismatch.
446
+ - [CVE-2026-34831](https://github.com/advisories/GHSA-q2ww-5357-x388) `Content-Length` mismatch in `Rack::Files` error responses.
447
+ - [CVE-2026-34826](https://github.com/advisories/GHSA-x8cg-fq8g-mxfx) Multipart byte range processing allows denial of service via excessive overlapping ranges.
448
+ - [CVE-2026-34830](https://github.com/advisories/GHSA-qv7j-4883-hwh7) `Rack::Sendfile` header-based `X-Accel-Mapping` regex injection enables unauthorized `X-Accel-Redirect`.
449
+ - [CVE-2026-34785](https://github.com/advisories/GHSA-h2jq-g4cq-5ppq) `Rack::Static` prefix matching can expose unintended files under the static root.
450
+ - [CVE-2026-34829](https://github.com/advisories/GHSA-8vqr-qjwx-82mw) Multipart parsing without `Content-Length` header allows unbounded chunked file uploads.
451
+
413
452
  ## [2.2.22] - 2026-02-16
414
453
 
415
454
  ### Security
@@ -115,7 +115,11 @@ module Rack
115
115
  unless data[1].empty?
116
116
  raise Error, "whitespace between boundary parameter name and equal sign"
117
117
  end
118
- if data.post_match.match?(/boundary\s*=/i)
118
+ # Count across the whole header rather than only after the match: the
119
+ # lazy prefix in MULTIPART can skip a first boundary parameter whose
120
+ # value is empty or starts with a quote, semicolon, or comma. Also
121
+ # count RFC 2231 boundary* parameters, which some parsers prefer.
122
+ if content_type.scan(/boundary(?:\*\d*\*?)?\s*=/i).size > 1
119
123
  raise BoundaryTooLongError, "multiple boundary parameters found in multipart content type"
120
124
  end
121
125
 
@@ -360,13 +364,19 @@ module Rack
360
364
 
361
365
  CONTENT_DISPOSITION_MAX_PARAMS = 16
362
366
  CONTENT_DISPOSITION_MAX_BYTES = 1536
367
+ OBS_UNFOLD = /\r\n([ \t])/
368
+ private_constant :OBS_UNFOLD
363
369
  def handle_mime_head
364
370
  if @sbuf.scan_until(@head_regex)
365
371
  head = @sbuf[1]
366
372
  content_type = head[MULTIPART_CONTENT_TYPE, 1]
373
+ content_type.gsub!(OBS_UNFOLD, '\\1') if content_type
367
374
  if (disposition = head[MULTIPART_CONTENT_DISPOSITION, 1]) &&
368
375
  disposition.bytesize <= CONTENT_DISPOSITION_MAX_BYTES
369
376
 
377
+ # Implement OBS unfolding (RFC 5322 Section 2.2.3)
378
+ disposition.gsub!(OBS_UNFOLD, '\\1')
379
+
370
380
  # ignore actual content-disposition value (should always be form-data)
371
381
  i = disposition.index(';')
372
382
  disposition.slice!(0, i+1)
@@ -479,6 +489,7 @@ module Rack
479
489
  # buffering. Note that the actual limit is the higher of 64KB and the buffer size (1MB by default)
480
490
  raise Error, "multipart mime part header too large" if @sbuf.rest.bytesize > MIME_HEADER_BYTESIZE_LIMIT
481
491
 
492
+ @sbuf.string = @sbuf.rest
482
493
  return :want_read
483
494
  end
484
495
  end
@@ -499,8 +510,8 @@ module Rack
499
510
  update_retained_size(body.bytesize) if @body_retained
500
511
  @collector.on_mime_body @mime_index, body
501
512
  @sbuf.pos += delta
502
- @sbuf.string = @sbuf.rest
503
513
  end
514
+ @sbuf.string = @sbuf.rest
504
515
  :want_read
505
516
  end
506
517
  end
data/lib/rack/request.rb CHANGED
@@ -320,8 +320,10 @@ module Rack
320
320
  end
321
321
 
322
322
  def host_with_port(authority = self.authority)
323
- host, _, port = split_authority(authority)
323
+ parts = split_authority(authority)
324
+ return nil if parts.empty?
324
325
 
326
+ host, _, port = parts
325
327
  if port == DEFAULT_PORTS[self.scheme]
326
328
  host
327
329
  else
@@ -591,7 +593,8 @@ module Rack
591
593
  end
592
594
 
593
595
  def base_url
594
- "#{scheme}://#{host_with_port}"
596
+ hostport = host_with_port || host_with_port(server_authority)
597
+ "#{scheme}://#{hostport}"
595
598
  end
596
599
 
597
600
  # Tries to return a remake of the original request URL as a string.
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/utils.rb CHANGED
@@ -146,8 +146,8 @@ module Rack
146
146
  end
147
147
  end
148
148
 
149
- ALLOWED_FORWARED_PARAMS = %w[by for host proto].to_h { |name| [name, name.to_sym] }.freeze
150
- private_constant :ALLOWED_FORWARED_PARAMS
149
+ ALLOWED_FORWARDED_PARAMS = %w[by for host proto].map { |name| [name, name.to_sym] }.to_h.freeze
150
+ private_constant :ALLOWED_FORWARDED_PARAMS
151
151
 
152
152
  def forwarded_values(forwarded_header)
153
153
  return unless forwarded_header
@@ -170,7 +170,7 @@ module Rack
170
170
  param.chomp!('=')
171
171
  param.strip!
172
172
  param.downcase!
173
- return unless param = ALLOWED_FORWARED_PARAMS[param]
173
+ return unless param = ALLOWED_FORWARDED_PARAMS[param]
174
174
 
175
175
  if header[0] == '"'
176
176
  # Parameter value is quoted, parse it, handling backslash escapes
data/lib/rack/version.rb CHANGED
@@ -12,7 +12,7 @@
12
12
  # so it should be enough just to <tt>require 'rack'</tt> in your code.
13
13
 
14
14
  module Rack
15
- RELEASE = "3.1.21"
15
+ RELEASE = "3.1.23"
16
16
 
17
17
  # Return the Rack release as a dotted string.
18
18
  def self.release
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: 3.1.21
4
+ version: 3.1.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leah Neukirchen
@@ -156,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
158
  requirements: []
159
- rubygems_version: 4.0.6
159
+ rubygems_version: 4.0.10
160
160
  specification_version: 4
161
161
  summary: A modular Ruby webserver interface.
162
162
  test_files: []