Skip to content

Commit 6b18ca4

Browse files
authored
Merge pull request #209 from koic/avoid_redos_in_ruby_3_1_and_earlier
Fix ReDoS vulnerability in `StringUtils#underscore`
2 parents b92dbe4 + 248b4d2 commit 6b18ca4

File tree

2 files changed

+16
-2
lines changed

2 files changed

+16
-2
lines changed

lib/mcp/string_utils.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ def demodulize(path)
1616

1717
def underscore(camel_cased_word)
1818
camel_cased_word
19-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
20-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
19+
.gsub(/(?<=[A-Z])(?=[A-Z][a-z])/, "_")
20+
.gsub(/(?<=[a-z\d])(?=[A-Z])/, "_")
2121
.tr("-", "_")
2222
.downcase
2323
end

test/mcp/string_utils_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require "test_helper"
4+
require "timeout"
45

56
module MCP
67
class StringUtilsTest < Minitest::Test
@@ -18,5 +19,18 @@ def test_handle_from_class_name_returns_the_class_name_without_the_module_for_a_
1819
assert_equal("test", StringUtils.handle_from_class_name("Module::Submodule::Test"))
1920
assert_equal("test_class", StringUtils.handle_from_class_name("Module::Submodule::TestClass"))
2021
end
22+
23+
def test_handle_from_class_name_does_not_cause_redos
24+
# A long string of uppercase letters followed by a non-lowercase character
25+
# would trigger catastrophic backtracking with the vulnerable regex patterns.
26+
malicious_input = "A" * 50_000 + "!"
27+
28+
result = nil
29+
Timeout.timeout(1) do
30+
result = StringUtils.handle_from_class_name(malicious_input)
31+
end
32+
33+
assert_equal("a" * 50_000 + "!", result)
34+
end
2135
end
2236
end

0 commit comments

Comments
 (0)