Fix ReDoS vulnerability in StringUtils#underscore

## Summary

Replace regex patterns with lookahead/lookbehind assertions to prevent
catastrophic backtracking on Ruby 3.1 and earlier.

This issue only affects Ruby 3.1 and earlier. Since it does not occur on Ruby 3.2+,
it is not an issue in the current stable release (0.4.0), which does not include #206.

## Regression Testing

Ensure the regex patterns complete within 1 second for a 50,000-character input
that would otherwise trigger superlinear backtracking.
This commit is contained in:
Koichi ITO 2026-01-09 01:14:52 +09:00
commit 248b4d2dad

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