Skip to content

Commit c5c3ab9

Browse files
committed
Rack: backport fix for CVE-2025-49007
1 parent 50de263 commit c5c3ab9

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

rack/lib/rack/multipart.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Multipart
88
autoload :Generator, 'rack/multipart/generator'
99

1010
EOL = "\r\n"
11+
FWS = /[ \t]+(?:\r\n[ \t]+)?/ # whitespace with optional folding
12+
HEADER_VALUE = "(?:[^\r\n]|\r\n[ \t])*" # anything but a non-folding CRLF
1113
MULTIPART_BOUNDARY = "AaB03x"
1214
MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
1315
TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
@@ -16,9 +18,12 @@ module Multipart
1618
RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i
1719
VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/
1820
BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i
19-
MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
20-
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:[^:]*;\s+name="?([^\";]*)"?/ni
21-
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
21+
22+
MULTIPART_CONTENT_TYPE = /^Content-Type:#{FWS}?(#{HEADER_VALUE})/ni
23+
MULTIPART_CONTENT_DISPOSITION = /^Content-Disposition:#{FWS}?(#{HEADER_VALUE})/ni
24+
MULTIPART_CONTENT_ID = /^Content-ID:#{FWS}?(#{HEADER_VALUE})/ni
25+
26+
MULTIPART_CONTENT_DISPOSITION_NAME = /;\s+name="?([^\";]*)"?/ni
2227

2328
class << self
2429
def parse_multipart(env)

rack/lib/rack/multipart/parser.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def get_current_head_and_filename_and_content_type_and_name_and_body
117117
@buf.slice!(0, 2) # Second \r\n
118118

119119
content_type = head[MULTIPART_CONTENT_TYPE, 1]
120-
name = head[MULTIPART_CONTENT_DISPOSITION, 1] || head[MULTIPART_CONTENT_ID, 1]
120+
name = get_name(head)
121121

122122
filename = get_filename(head)
123123

@@ -145,6 +145,13 @@ def get_current_head_and_filename_and_content_type_and_name_and_body
145145
[head, filename, content_type, name, body]
146146
end
147147

148+
def get_name(head)
149+
name = if (disposition_value = head[MULTIPART_CONTENT_DISPOSITION, 1])
150+
disposition_value[MULTIPART_CONTENT_DISPOSITION_NAME, 1]
151+
end
152+
name || head[MULTIPART_CONTENT_ID, 1]
153+
end
154+
148155
def get_filename(head)
149156
filename = nil
150157
if head =~ RFC2183

0 commit comments

Comments
 (0)