Skip to content

Commit 6693ba5

Browse files
denzelemcodener
authored andcommitted
Fix [CVE-2024-47889]: Avoid backtracking in ActionMailer block_format
1 parent f4b8fe2 commit 6693ba5

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

actionmailer/lib/action_mailer/mail_helper.rb

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@ module MailHelper
22
# Uses Text::Format to take the text and format it, indented two spaces for
33
# each line, and wrapped at 72 columns.
44
def block_format(text)
5-
formatted = text.split(/\n\r\n/).collect { |paragraph|
5+
formatted = text.split(/\n\r\n/).collect { |paragraph|
66
Text::Format.new(
77
:columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
88
).format
99
}.join("\n")
10-
10+
1111
# Make list points stand on their own line
12-
formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
13-
formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
12+
output = ""
13+
splits = formatted.split(/(\*+|\#+)/)
14+
while line = splits.shift
15+
if line.start_with?("*", "#") && splits[0] && splits[0].start_with?(" ")
16+
output.chomp!(" ") while output.end_with?(" ")
17+
output << " #{line} #{splits.shift.strip}\n"
18+
else
19+
output << line
20+
end
21+
end
1422

15-
formatted
23+
output
1624
end
1725
end

actionmailer/test/mail_helper_test.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,36 @@ def test_use_mail_helper
9191
assert_match %r{ But soft!}, mail.encoded
9292
assert_match %r{east, and\n Juliet}, mail.encoded
9393
end
94+
95+
def helper
96+
Object.new.extend(MailHelper)
97+
end
98+
99+
def test_block_format
100+
assert_equal " * foo\n", helper.block_format(" * foo")
101+
assert_equal " * foo\n", helper.block_format(" * foo")
102+
assert_equal " * foo\n", helper.block_format("* foo")
103+
assert_equal " * foo\n*bar\n", helper.block_format("* foo*bar")
104+
assert_equal " * foo\n * bar\n", helper.block_format("* foo * bar")
105+
assert_equal " *\n", helper.block_format("* ")
106+
end
107+
108+
# Test case for CVE-2024-47889
109+
def test_block_format_asterisk
110+
assert_nothing_raised do
111+
Timeout.timeout(0.1) do
112+
helper.block_format(' ' + '*' * 50_000)
113+
end
114+
end
115+
end
116+
117+
# Test case for CVE-2024-47889
118+
def test_block_format_hashtag
119+
assert_nothing_raised do
120+
Timeout.timeout(0.1) do
121+
helper.block_format(' ' + '#' * 50_000)
122+
end
123+
end
124+
end
94125
end
95126

0 commit comments

Comments
 (0)