fix: mitigate ReDoS in to_duration via max input length check (closes #494) (#523)

This commit is contained in:
Christian Heinrich Hohlfeld 2025-04-22 00:16:33 +02:00 committed by GitHub
parent 63962343d9
commit 3c12e99970
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 0 deletions

View File

@ -34,6 +34,7 @@ from timezonefinder import TimezoneFinder
from akkudoktoreos.core.logging import get_logger from akkudoktoreos.core.logging import get_logger
logger = get_logger(__name__) logger = get_logger(__name__)
MAX_DURATION_STRING_LENGTH = 350
@overload @overload
@ -287,6 +288,11 @@ def to_duration(
"second": 1, "second": 1,
} }
# Mitigate ReDoS vulnerability (#494) by checking input string length.
if len(input_value) > MAX_DURATION_STRING_LENGTH:
raise ValueError(
f"Input string exceeds maximum allowed length ({MAX_DURATION_STRING_LENGTH})."
)
# Regular expression to match time components like '2 days', '5 hours', etc. # Regular expression to match time components like '2 days', '5 hours', etc.
matches = re.findall(r"(\d+)\s*(days?|hours?|minutes?|seconds?)", input_value) matches = re.findall(r"(\d+)\s*(days?|hours?|minutes?|seconds?)", input_value)

View File

@ -1,10 +1,13 @@
"""Test Module for pendulum.datetimeutil Module.""" """Test Module for pendulum.datetimeutil Module."""
import re
import pendulum import pendulum
import pytest import pytest
from pendulum.tz.timezone import Timezone from pendulum.tz.timezone import Timezone
from akkudoktoreos.utils.datetimeutil import ( from akkudoktoreos.utils.datetimeutil import (
MAX_DURATION_STRING_LENGTH,
compare_datetimes, compare_datetimes,
hours_in_day, hours_in_day,
to_datetime, to_datetime,
@ -620,3 +623,33 @@ def test_compare_datetimes_gt(dt1, dt2):
assert compare_datetimes(dt1, dt2).gt assert compare_datetimes(dt1, dt2).gt
assert compare_datetimes(dt1, dt2).le == False assert compare_datetimes(dt1, dt2).le == False
assert compare_datetimes(dt1, dt2).lt == False assert compare_datetimes(dt1, dt2).lt == False
def test_to_duration_excessive_length_raises_valueerror():
"""Test that to_duration raises ValueError for strings exceeding max length.
This test covers the fix for the ReDoS vulnerability.
Related to: #494
"""
# String exceeds limits
long_string = "a" * (MAX_DURATION_STRING_LENGTH + 50)
# Expected Errormessage ESCAPED für Regex
expected_error_message = re.escape(
f"Input string exceeds maximum allowed length ({MAX_DURATION_STRING_LENGTH})."
)
# Check if error was raised
with pytest.raises(ValueError, match=expected_error_message):
to_duration(long_string)
# Optional: String exactly at the limit should NOT trigger the length check.
at_limit_string = "b" * MAX_DURATION_STRING_LENGTH
try:
to_duration(at_limit_string)
except ValueError as e:
if str(e) == f"Input string exceeds maximum allowed length ({MAX_DURATION_STRING_LENGTH}).":
pytest.fail(
f"to_duration raised length ValueError unexpectedly for string at limit: {at_limit_string}"
)
pass