rack 3.2.1 → 3.2.3

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: 32413bcd1f96d1cc6283491c3a7cf4b0301d9eb84d7d334895586d42981f0858
4
- data.tar.gz: ecd4aaba754ab7de09ced1dab1efb3366242933edeb1e549aaa14cdec1ff3cfc
3
+ metadata.gz: 19fbcf7ac3f253dc5265f02aa7200b80293cba9497712bef24b3bd9af9a7e1e8
4
+ data.tar.gz: fb0dbfc721493fa7483ba1cb4a258b246823bcc2e42dff2ee69519be653ade80
5
5
  SHA512:
6
- metadata.gz: bdf1806a0951c9523e75fe5a4be2eed0536c9e313b6f6808bb0ec7c43d62d489d63f75cb1e2a2a6741468d9fd2b34bb4ff22f0f8d32b5c3a0d3271faf2b11e73
7
- data.tar.gz: 98183f1e7637e3e9fa3a2b32908c8b00acdf294b526c413393eaff99daf6bf4e103c5501efe87fea54435747b7a782801e54dfbd89781513557ed56f047a1f1a
6
+ metadata.gz: 44fcb08953ddacf0c82e60513ea4642d95f330fc82d1f4bf06bb8bc9f1e26eb9d19c9c48bf73b639e2b2427173660e1a3d553358b8b536c4236c3e44af2f87df
7
+ data.tar.gz: 584b4862cdab33cb37aca49446d3c0bef33c37a4f9a63c5238105d601c23b86c54ab3b277a570b465590006fcf8edbcd8a8b195fa07f0f40375a3b988b299433
data/CHANGELOG.md CHANGED
@@ -2,7 +2,20 @@
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
- ## Unreleased
5
+ ## [3.2.3] - 2025-10-10
6
+
7
+ ### Security
8
+
9
+ - [CVE-2025-61780](https://github.com/advisories/GHSA-r657-rxjc-j557) Improper handling of headers in `Rack::Sendfile` may allow proxy bypass.
10
+ - [CVE-2025-61919](https://github.com/advisories/GHSA-6xw4-3v39-52mm) Unbounded read in `Rack::Request` form parsing can lead to memory exhaustion.
11
+
12
+ ## [3.2.2] - 2025-10-07
13
+
14
+ ### Security
15
+
16
+ - [CVE-2025-61772](https://github.com/advisories/GHSA-wpv5-97wm-hp9c) Multipart parser buffers unbounded per-part headers, enabling DoS (memory exhaustion)
17
+ - [CVE-2025-61771](https://github.com/advisories/GHSA-w9pc-fmgc-vxvw) Multipart parser buffers large non‑file fields entirely in memory, enabling DoS (memory exhaustion)
18
+ - [CVE-2025-61770](https://github.com/advisories/GHSA-p543-xpfm-54cp) Unbounded multipart preamble buffering enables DoS (memory exhaustion)
6
19
 
7
20
  ## [3.2.1] -- 2025-09-02
8
21
 
@@ -61,6 +74,21 @@ This release continues Rack's evolution toward a cleaner, more efficient foundat
61
74
  - `SERVER_NAME` and `HTTP_HOST` are now more strictly validated according to the relevant specifications. ([#2298](https://github.com/rack/rack/pull/2298), [@ioquatix])
62
75
  - `Rack::Lint` now disallows `PATH_INFO="" SCRIPT_NAME=""`. ([#2298](https://github.com/rack/rack/issues/2307), [@jeremyevans])
63
76
 
77
+ ## [3.1.18] - 2025-10-10
78
+
79
+ ### Security
80
+
81
+ - [CVE-2025-61780](https://github.com/advisories/GHSA-r657-rxjc-j557) Improper handling of headers in `Rack::Sendfile` may allow proxy bypass.
82
+ - [CVE-2025-61919](https://github.com/advisories/GHSA-6xw4-3v39-52mm) Unbounded read in `Rack::Request` form parsing can lead to memory exhaustion.
83
+
84
+ ## [3.1.17] - 2025-10-07
85
+
86
+ ### Security
87
+
88
+ - [CVE-2025-61772](https://github.com/advisories/GHSA-wpv5-97wm-hp9c) Multipart parser buffers unbounded per-part headers, enabling DoS (memory exhaustion)
89
+ - [CVE-2025-61771](https://github.com/advisories/GHSA-w9pc-fmgc-vxvw) Multipart parser buffers large non‑file fields entirely in memory, enabling DoS (memory exhaustion)
90
+ - [CVE-2025-61770](https://github.com/advisories/GHSA-p543-xpfm-54cp) Unbounded multipart preamble buffering enables DoS (memory exhaustion)
91
+
64
92
  ## [3.1.16] - 2025-06-04
65
93
 
66
94
  ### Security
@@ -77,7 +105,7 @@ This release continues Rack's evolution toward a cleaner, more efficient foundat
77
105
 
78
106
  ### Security
79
107
 
80
- - [CVE-2025-46727](https://github.com/rack/rack/security/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
108
+ - [CVE-2025-46727](https://github.com/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
81
109
 
82
110
  ## [3.1.13] - 2025-04-13
83
111
 
@@ -87,19 +115,19 @@ This release continues Rack's evolution toward a cleaner, more efficient foundat
87
115
 
88
116
  ### Security
89
117
 
90
- - [CVE-2025-27610](https://github.com/rack/rack/security/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
118
+ - [CVE-2025-27610](https://github.com/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
91
119
 
92
120
  ## [3.1.11] - 2025-03-04
93
121
 
94
122
  ### Security
95
123
 
96
- - [CVE-2025-27111](https://github.com/rack/rack/security/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
124
+ - [CVE-2025-27111](https://github.com/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
97
125
 
98
126
  ## [3.1.10] - 2025-02-12
99
127
 
100
128
  ### Security
101
129
 
102
- - [CVE-2025-25184](https://github.com/rack/rack/security/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
130
+ - [CVE-2025-25184](https://github.com/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
103
131
 
104
132
  ## [3.1.9] - 2025-01-31
105
133
 
@@ -132,7 +160,7 @@ This release continues Rack's evolution toward a cleaner, more efficient foundat
132
160
 
133
161
  ### Security
134
162
 
135
- - Fix potential ReDoS attack in `Rack::Request#parse_http_accept_header`. ([GHSA-cj83-2ww7-mvq7](https://github.com/rack/rack/security/advisories/GHSA-cj83-2ww7-mvq7), [@dwisiswant0](https://github.com/dwisiswant0))
163
+ - Fix potential ReDoS attack in `Rack::Request#parse_http_accept_header`. ([GHSA-cj83-2ww7-mvq7](https://github.com/advisories/GHSA-cj83-2ww7-mvq7), [@dwisiswant0](https://github.com/dwisiswant0))
136
164
 
137
165
  ## [3.1.4] - 2024-06-22
138
166
 
@@ -224,7 +252,7 @@ This release is primarily a maintenance release that removes features deprecated
224
252
 
225
253
  ### Security
226
254
 
227
- - [CVE-2025-46727](https://github.com/rack/rack/security/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
255
+ - [CVE-2025-46727](https://github.com/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
228
256
 
229
257
  ## [3.0.15] - 2025-04-13
230
258
 
@@ -234,13 +262,13 @@ This release is primarily a maintenance release that removes features deprecated
234
262
 
235
263
  ### Security
236
264
 
237
- - [CVE-2025-27610](https://github.com/rack/rack/security/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
265
+ - [CVE-2025-27610](https://github.com/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
238
266
 
239
267
  ## [3.0.13] - 2025-03-04
240
268
 
241
269
  ### Security
242
270
 
243
- - [CVE-2025-27111](https://github.com/rack/rack/security/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
271
+ - [CVE-2025-27111](https://github.com/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
244
272
 
245
273
  ### Fixed
246
274
 
@@ -250,7 +278,7 @@ This release is primarily a maintenance release that removes features deprecated
250
278
 
251
279
  ### Security
252
280
 
253
- - [CVE-2025-25184](https://github.com/rack/rack/security/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
281
+ - [CVE-2025-25184](https://github.com/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
254
282
 
255
283
  ## [3.0.11] - 2024-05-10
256
284
 
@@ -430,6 +458,27 @@ This release introduces major improvements to Rack, including enhanced support f
430
458
  - 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))
431
459
  - `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))
432
460
 
461
+ ## [2.2.20] - 2025-10-10
462
+
463
+ ### Security
464
+
465
+ - [CVE-2025-61780](https://github.com/advisories/GHSA-r657-rxjc-j557) Improper handling of headers in `Rack::Sendfile` may allow proxy bypass.
466
+ - [CVE-2025-61919](https://github.com/advisories/GHSA-6xw4-3v39-52mm) Unbounded read in `Rack::Request` form parsing can lead to memory exhaustion.
467
+
468
+ ## [2.2.19] - 2025-10-07
469
+
470
+ ### Security
471
+
472
+ - [CVE-2025-61772](https://github.com/advisories/GHSA-wpv5-97wm-hp9c) Multipart parser buffers unbounded per-part headers, enabling DoS (memory exhaustion)
473
+ - [CVE-2025-61771](https://github.com/advisories/GHSA-w9pc-fmgc-vxvw) Multipart parser buffers large non‑file fields entirely in memory, enabling DoS (memory exhaustion)
474
+ - [CVE-2025-61770](https://github.com/advisories/GHSA-p543-xpfm-54cp) Unbounded multipart preamble buffering enables DoS (memory exhaustion)
475
+
476
+ ## [2.2.18] - 2025-09-25
477
+
478
+ ### Security
479
+
480
+ - [CVE-2025-59830](https://github.com/advisories/GHSA-625h-95r8-8xpm) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion via semicolon-separated parameters.
481
+
433
482
  ## [2.2.17] - 2025-06-03
434
483
 
435
484
  - Backport `Rack::MediaType#params` now handles parameters without values. ([#2263](https://github.com/rack/rack/pull/2263), [@AllyMarthaJ](https://github.com/AllyMarthaJ))
@@ -448,25 +497,25 @@ This release introduces major improvements to Rack, including enhanced support f
448
497
 
449
498
  ### Security
450
499
 
451
- - [CVE-2025-46727](https://github.com/rack/rack/security/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
500
+ - [CVE-2025-46727](https://github.com/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
452
501
 
453
502
  ## [2.2.13] - 2025-03-11
454
503
 
455
504
  ### Security
456
505
 
457
- - [CVE-2025-27610](https://github.com/rack/rack/security/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
506
+ - [CVE-2025-27610](https://github.com/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
458
507
 
459
508
  ## [2.2.12] - 2025-03-04
460
509
 
461
510
  ### Security
462
511
 
463
- - [CVE-2025-27111](https://github.com/rack/rack/security/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
512
+ - [CVE-2025-27111](https://github.com/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
464
513
 
465
514
  ## [2.2.11] - 2025-02-12
466
515
 
467
516
  ### Security
468
517
 
469
- - [CVE-2025-25184](https://github.com/rack/rack/security/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
518
+ - [CVE-2025-25184](https://github.com/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
470
519
 
471
520
  ## [2.2.10] - 2024-10-14
472
521
 
data/README.md CHANGED
@@ -230,6 +230,14 @@ query string, before attempting parsing, so if the same parameter key is
230
230
  used multiple times in the query, each counts as a separate parameter for
231
231
  this check.
232
232
 
233
+ ### `RACK_MULTIPART_BUFFERED_UPLOAD_BYTESIZE_LIMIT`
234
+
235
+ This environment variable sets the maximum amount of memory Rack will use
236
+ to buffer multipart parameters when parsing a request body. This considers
237
+ the size of the multipart mime headers and the body part for multipart
238
+ parameters that are buffered in memory and do not use tempfiles. This
239
+ defaults to 16MB if not provided.
240
+
233
241
  ### `param_depth_limit`
234
242
 
235
243
  ```ruby
@@ -59,6 +59,27 @@ module Rack
59
59
  Tempfile.new(["RackMultipart", extension])
60
60
  }
61
61
 
62
+ BOUNDARY_START_LIMIT = 16 * 1024
63
+ private_constant :BOUNDARY_START_LIMIT
64
+
65
+ MIME_HEADER_BYTESIZE_LIMIT = 64 * 1024
66
+ private_constant :MIME_HEADER_BYTESIZE_LIMIT
67
+
68
+ env_int = lambda do |key, val|
69
+ if str_val = ENV[key]
70
+ begin
71
+ val = Integer(str_val, 10)
72
+ rescue ArgumentError
73
+ raise ArgumentError, "non-integer value provided for environment variable #{key}"
74
+ end
75
+ end
76
+
77
+ val
78
+ end
79
+
80
+ BUFFERED_UPLOAD_BYTESIZE_LIMIT = env_int.call("RACK_MULTIPART_BUFFERED_UPLOAD_BYTESIZE_LIMIT", 16 * 1024 * 1024)
81
+ private_constant :BUFFERED_UPLOAD_BYTESIZE_LIMIT
82
+
62
83
  class BoundedIO # :nodoc:
63
84
  def initialize(io, content_length)
64
85
  @io = io
@@ -218,6 +239,8 @@ module Rack
218
239
 
219
240
  @state = :FAST_FORWARD
220
241
  @mime_index = 0
242
+ @body_retained = nil
243
+ @retained_size = 0
221
244
  @collector = Collector.new tempfile
222
245
 
223
246
  @sbuf = StringScanner.new("".dup)
@@ -294,6 +317,10 @@ module Rack
294
317
 
295
318
  # retry for opening boundary
296
319
  else
320
+ # We raise if we don't find the multipart boundary, to avoid unbounded memory
321
+ # buffering. Note that the actual limit is the higher of 16KB and the buffer size (1MB by default)
322
+ raise Error, "multipart boundary not found within limit" if @sbuf.string.bytesize > BOUNDARY_START_LIMIT
323
+
297
324
  # no boundary found, keep reading data
298
325
  return :want_read
299
326
  end
@@ -410,16 +437,30 @@ module Rack
410
437
  name = filename || "#{content_type || TEXT_PLAIN}[]".dup
411
438
  end
412
439
 
440
+ # Mime part head data is retained for both TempfilePart and BufferPart
441
+ # for the entireity of the parse, even though it isn't used for BufferPart.
442
+ update_retained_size(head.bytesize)
443
+
444
+ # If a filename is given, a TempfilePart will be used, so the body will
445
+ # not be buffered in memory. However, if a filename is not given, a BufferPart
446
+ # will be used, and the body will be buffered in memory.
447
+ @body_retained = !filename
448
+
413
449
  @collector.on_mime_head @mime_index, head, filename, content_type, name
414
450
  @state = :MIME_BODY
415
451
  else
416
- :want_read
452
+ # We raise if the mime part header is too large, to avoid unbounded memory
453
+ # buffering. Note that the actual limit is the higher of 64KB and the buffer size (1MB by default)
454
+ raise Error, "multipart mime part header too large" if @sbuf.string.bytesize > MIME_HEADER_BYTESIZE_LIMIT
455
+
456
+ return :want_read
417
457
  end
418
458
  end
419
459
 
420
460
  def handle_mime_body
421
461
  if (body_with_boundary = @sbuf.check_until(@body_regex)) # check but do not advance the pointer yet
422
462
  body = body_with_boundary.sub(@body_regex_at_end, '') # remove the boundary from the string
463
+ update_retained_size(body.bytesize) if @body_retained
423
464
  @collector.on_mime_body @mime_index, body
424
465
  @sbuf.pos += body.length + 2 # skip \r\n after the content
425
466
  @state = :CONSUME_TOKEN
@@ -428,7 +469,9 @@ module Rack
428
469
  # Save what we have so far
429
470
  if @rx_max_size < @sbuf.rest_size
430
471
  delta = @sbuf.rest_size - @rx_max_size
431
- @collector.on_mime_body @mime_index, @sbuf.peek(delta)
472
+ body = @sbuf.peek(delta)
473
+ update_retained_size(body.bytesize) if @body_retained
474
+ @collector.on_mime_body @mime_index, body
432
475
  @sbuf.pos += delta
433
476
  @sbuf.string = @sbuf.rest
434
477
  end
@@ -436,6 +479,13 @@ module Rack
436
479
  end
437
480
  end
438
481
 
482
+ def update_retained_size(size)
483
+ @retained_size += size
484
+ if @retained_size > BUFFERED_UPLOAD_BYTESIZE_LIMIT
485
+ raise Error, "multipart data over retained size limit"
486
+ end
487
+ end
488
+
439
489
  # Scan until the we find the start or end of the boundary.
440
490
  # If we find it, return the appropriate symbol for the start or
441
491
  # end of the boundary. If we don't find the start or end of the
@@ -57,6 +57,8 @@ module Rack
57
57
  PARAMS_LIMIT = env_int.call("RACK_QUERY_PARSER_PARAMS_LIMIT", 4096)
58
58
  private_constant :PARAMS_LIMIT
59
59
 
60
+ attr_reader :bytesize_limit
61
+
60
62
  def initialize(params_class, param_depth_limit, bytesize_limit: BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT)
61
63
  @params_class = params_class
62
64
  @param_depth_limit = param_depth_limit
@@ -221,7 +223,7 @@ module Rack
221
223
  return if !qs || qs.empty?
222
224
 
223
225
  if qs.bytesize > @bytesize_limit
224
- raise QueryLimitError, "total query size (#{qs.bytesize}) exceeds limit (#{@bytesize_limit})"
226
+ raise QueryLimitError, "total query size exceeds limit (#{@bytesize_limit})"
225
227
  end
226
228
 
227
229
  pairs = qs.split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP, @params_limit + 1)
data/lib/rack/request.rb CHANGED
@@ -513,7 +513,10 @@ module Rack
513
513
  if pairs = Rack::Multipart.parse_multipart(env, Rack::Multipart::ParamList)
514
514
  set_header RACK_REQUEST_FORM_PAIRS, pairs
515
515
  else
516
- form_vars = get_header(RACK_INPUT).read
516
+ # Add 2 bytes. One to check whether it is over the limit, and a second
517
+ # in case the slice! call below removes the last byte
518
+ # If read returns nil, use the empty string
519
+ form_vars = get_header(RACK_INPUT).read(query_parser.bytesize_limit + 2) || ''
517
520
 
518
521
  # Fix for Safari Ajax postings that always append \0
519
522
  # form_vars.sub!(/\0\z/, '') # performance replacement:
data/lib/rack/sendfile.rb CHANGED
@@ -16,21 +16,21 @@ module Rack
16
16
  # delivery code.
17
17
  #
18
18
  # In order to take advantage of this middleware, the response body must
19
- # respond to +to_path+ and the request must include an x-sendfile-type
19
+ # respond to +to_path+ and the request must include an `x-sendfile-type`
20
20
  # header. Rack::Files and other components implement +to_path+ so there's
21
- # rarely anything you need to do in your application. The x-sendfile-type
21
+ # rarely anything you need to do in your application. The `x-sendfile-type`
22
22
  # header is typically set in your web servers configuration. The following
23
23
  # sections attempt to document
24
24
  #
25
25
  # === Nginx
26
26
  #
27
- # Nginx supports the x-accel-redirect header. This is similar to x-sendfile
27
+ # Nginx supports the `x-accel-redirect` header. This is similar to `x-sendfile`
28
28
  # but requires parts of the filesystem to be mapped into a private URL
29
29
  # hierarchy.
30
30
  #
31
31
  # The following example shows the Nginx configuration required to create
32
- # a private "/files/" area, enable x-accel-redirect, and pass the special
33
- # x-sendfile-type and x-accel-mapping headers to the backend:
32
+ # a private "/files/" area, enable `x-accel-redirect`, and pass the special
33
+ # `x-accel-mapping` header to the backend:
34
34
  #
35
35
  # location ~ /files/(.*) {
36
36
  # internal;
@@ -44,24 +44,29 @@ module Rack
44
44
  # proxy_set_header X-Real-IP $remote_addr;
45
45
  # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
46
46
  #
47
- # proxy_set_header x-sendfile-type x-accel-redirect;
48
47
  # proxy_set_header x-accel-mapping /var/www/=/files/;
49
48
  #
50
49
  # proxy_pass http://127.0.0.1:8080/;
51
50
  # }
52
51
  #
53
- # Note that the x-sendfile-type header must be set exactly as shown above.
54
- # The x-accel-mapping header should specify the location on the file system,
52
+ # The `x-accel-mapping` header should specify the location on the file system,
55
53
  # followed by an equals sign (=), followed name of the private URL pattern
56
54
  # that it maps to. The middleware performs a simple substitution on the
57
55
  # resulting path.
58
56
  #
57
+ # To enable `x-accel-redirect`, you must configure the middleware explicitly:
58
+ #
59
+ # use Rack::Sendfile, "x-accel-redirect"
60
+ #
61
+ # For security reasons, the `x-sendfile-type` header from requests is ignored.
62
+ # The sendfile variation must be set via the middleware constructor.
63
+ #
59
64
  # See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile
60
65
  #
61
66
  # === lighttpd
62
67
  #
63
- # Lighttpd has supported some variation of the x-sendfile header for some
64
- # time, although only recent version support x-sendfile in a reverse proxy
68
+ # Lighttpd has supported some variation of the `x-sendfile` header for some
69
+ # time, although only recent version support `x-sendfile` in a reverse proxy
65
70
  # configuration.
66
71
  #
67
72
  # $HTTP["host"] == "example.com" {
@@ -83,7 +88,7 @@ module Rack
83
88
  #
84
89
  # === Apache
85
90
  #
86
- # x-sendfile is supported under Apache 2.x using a separate module:
91
+ # `x-sendfile` is supported under Apache 2.x using a separate module:
87
92
  #
88
93
  # https://tn123.org/mod_xsendfile/
89
94
  #
@@ -97,16 +102,28 @@ module Rack
97
102
  # === Mapping parameter
98
103
  #
99
104
  # The third parameter allows for an overriding extension of the
100
- # x-accel-mapping header. Mappings should be provided in tuples of internal to
105
+ # `x-accel-mapping` header. Mappings should be provided in tuples of internal to
101
106
  # external. The internal values may contain regular expression syntax, they
102
107
  # will be matched with case indifference.
108
+ #
109
+ # When `x-accel-redirect` is explicitly enabled via the variation parameter,
110
+ # and no application-level mappings are provided, the middleware will read
111
+ # the `x-accel-mapping` header from the proxy. This allows nginx to control
112
+ # the path mapping without requiring application-level configuration.
113
+ #
114
+ # === Security
115
+ #
116
+ # For security reasons, the `x-sendfile-type` header from HTTP requests is
117
+ # ignored. The sendfile variation must be explicitly configured via the
118
+ # middleware constructor to prevent information disclosure vulnerabilities
119
+ # where attackers could bypass proxy restrictions.
103
120
 
104
121
  class Sendfile
105
122
  def initialize(app, variation = nil, mappings = [])
106
123
  @app = app
107
124
  @variation = variation
108
125
  @mappings = mappings.map do |internal, external|
109
- [/^#{internal}/i, external]
126
+ [/\A#{internal}/i, external]
110
127
  end
111
128
  end
112
129
 
@@ -145,22 +162,35 @@ module Rack
145
162
  end
146
163
 
147
164
  private
165
+
148
166
  def variation(env)
149
- @variation ||
150
- env['sendfile.type'] ||
151
- env['HTTP_X_SENDFILE_TYPE']
167
+ # Note: HTTP_X_SENDFILE_TYPE is intentionally NOT read for security reasons.
168
+ # Attackers could use this header to enable x-accel-redirect and bypass proxy restrictions.
169
+ @variation || env['sendfile.type']
170
+ end
171
+
172
+ def x_accel_mapping(env)
173
+ # Only allow header when:
174
+ # 1. `x-accel-redirect` is explicitly enabled via constructor.
175
+ # 2. No application-level mappings are configured.
176
+ return nil unless @variation =~ /x-accel-redirect/i
177
+ return nil if @mappings.any?
178
+
179
+ env['HTTP_X_ACCEL_MAPPING']
152
180
  end
153
181
 
154
182
  def map_accel_path(env, path)
155
183
  if mapping = @mappings.find { |internal, _| internal =~ path }
156
- path.sub(*mapping)
157
- elsif mapping = env['HTTP_X_ACCEL_MAPPING']
184
+ return path.sub(*mapping)
185
+ elsif mapping = x_accel_mapping(env)
186
+ # Safe to use header: explicit config + no app mappings:
158
187
  mapping.split(',').map(&:strip).each do |m|
159
188
  internal, external = m.split('=', 2).map(&:strip)
160
- new_path = path.sub(/^#{internal}/i, external)
189
+ new_path = path.sub(/\A#{internal}/i, external)
161
190
  return new_path unless path == new_path
162
191
  end
163
- path
192
+
193
+ return path
164
194
  end
165
195
  end
166
196
  end
data/lib/rack/version.rb CHANGED
@@ -6,7 +6,7 @@
6
6
  # See MIT-LICENSE or https://opensource.org/licenses/MIT.
7
7
 
8
8
  module Rack
9
- VERSION = "3.2.1"
9
+ VERSION = "3.2.3"
10
10
 
11
11
  RELEASE = VERSION
12
12
 
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.2.1
4
+ version: 3.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leah Neukirchen