File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file. For info on
1919- [ CVE-2026 -34785] ( https://github.com/advisories/GHSA-h2jq-g4cq-5ppq ) ` Rack::Static ` prefix matching can expose unintended files under the static root.
2020- [ CVE-2026 -34829] ( https://github.com/advisories/GHSA-8vqr-qjwx-82mw ) Multipart parsing without ` Content-Length ` header allows unbounded chunked file uploads.
2121- [ 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.
22+ - [ CVE-2026 -26962] ( https://github.com/advisories/GHSA-rx22-g9mx-qrhv ) Improper unfolding of folded multipart headers preserves CRLF in parsed parameter values.
2223
2324### SPEC Changes
2425
Original file line number Diff line number Diff line change @@ -373,13 +373,21 @@ def handle_consume_token
373373
374374 CONTENT_DISPOSITION_MAX_PARAMS = 16
375375 CONTENT_DISPOSITION_MAX_BYTES = 1536
376+ OBS_UNFOLD = /\r \n ([ \t ])/
377+ private_constant :OBS_UNFOLD
378+
376379 def handle_mime_head
377380 if @sbuf . scan_until ( @head_regex )
378381 head = @sbuf [ 1 ]
379382 content_type = head [ MULTIPART_CONTENT_TYPE , 1 ]
383+ content_type . gsub! ( OBS_UNFOLD , '\1' ) if content_type
384+
380385 if ( disposition = head [ MULTIPART_CONTENT_DISPOSITION , 1 ] ) &&
381386 disposition . bytesize <= CONTENT_DISPOSITION_MAX_BYTES
382387
388+ # Implement OBS unfolding (RFC 5322 Section 2.2.3)
389+ disposition . gsub! ( OBS_UNFOLD , '\1' )
390+
383391 # ignore actual content-disposition value (should always be form-data)
384392 if i = disposition . index ( ';' )
385393 disposition . slice! ( 0 , i + 1 )
Original file line number Diff line number Diff line change @@ -1440,4 +1440,27 @@ def initialize(*)
14401440 params = Rack ::Multipart . parse_multipart ( env )
14411441 params [ "field" ] . must_equal "data"
14421442 end
1443+
1444+ it "prevents CRLF injection in parameter values via obs-fold" do
1445+ data = <<~EOF
1446+ --AaB03x\r
1447+ Content-Disposition: form-data; name="upload"; filename="test\r
1448+ \t .txt"\r
1449+ Content-Type: application/octet-stream;\r
1450+ name="file.php"\r
1451+ \r
1452+ <?php eval($_POST['x']); ?>\r
1453+ --AaB03x--\r
1454+ EOF
1455+
1456+ options = {
1457+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" ,
1458+ "CONTENT_LENGTH" => data . length . to_s ,
1459+ :input => StringIO . new ( data )
1460+ }
1461+ env = Rack ::MockRequest . env_for ( "/" , options )
1462+ params = Rack ::Multipart . parse_multipart ( env )
1463+ params [ "upload" ] [ :filename ] . must_equal "test\t .txt"
1464+ params [ "upload" ] [ :type ] . must_equal 'application/octet-stream; name="file.php"'
1465+ end
14431466end
You can’t perform that action at this time.
0 commit comments