Merge pull request #209 from koic/avoid_redos_in_ruby_3_1_and_earlier

Fix ReDoS vulnerability in `StringUtils#underscore`
This commit is contained in:
Koichi ITO 2026-01-10 01:16:27 +09:00 • committed by GitHub
commit 6b18ca41be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 16 additions and 2 deletions

View file

@ -16,8 +16,8 @@ module MCP
def underscore(camel_cased_word)
camel_cased_word
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
.gsub(/(?<=[A-Z])(?=[A-Z][a-z])/, "_")
.gsub(/(?<=[a-z\d])(?=[A-Z])/, "_")
.tr("-", "_")
.downcase
end

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require "test_helper"
require "timeout"
module MCP
class StringUtilsTest < Minitest::Test
@ -18,5 +19,18 @@ module MCP
assert_equal("test", StringUtils.handle_from_class_name("Module::Submodule::Test"))
assert_equal("test_class", StringUtils.handle_from_class_name("Module::Submodule::TestClass"))
end
def test_handle_from_class_name_does_not_cause_redos
# A long string of uppercase letters followed by a non-lowercase character
# would trigger catastrophic backtracking with the vulnerable regex patterns.
malicious_input = "A" * 50_000 + "!"
result = nil
Timeout.timeout(1) do
result = StringUtils.handle_from_class_name(malicious_input)
end
assert_equal("a" * 50_000 + "!", result)
end
end
end