From 2a663e807782951fa1872df9677d92867804bb71 Mon Sep 17 00:00:00 2001 From: Rustam Shaykhinurov Date: Sun, 22 Feb 2026 00:25:03 +0300 Subject: [PATCH] Fix DurationType regex vulnerability and add tests --- src/celpy/celtypes.py | 7 +++++-- tests/test_celtypes.py | 11 +++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/celpy/celtypes.py b/src/celpy/celtypes.py index d9e7548..772fa51 100644 --- a/src/celpy/celtypes.py +++ b/src/celpy/celtypes.py @@ -1347,7 +1347,10 @@ def __new__( raise ValueError("range error: {seconds}") return super().__new__(cls, seconds=seconds, microseconds=nanos // 1000) elif isinstance(seconds, str): - duration_pat = re.compile(r"^[-+]?([0-9]*(\.[0-9]*)?[a-z]+)+$") + valid_units = sorted(cls.scale.keys(), key=len, reverse=True) + units_pattern = r"(?:" + r"|".join(map(re.escape, valid_units)) + r")" + + duration_pat = re.compile(rf"^[-+]?([0-9]*(\.[0-9]*)?{units_pattern})+$") duration_match = duration_pat.match(seconds) if not duration_match: @@ -1369,7 +1372,7 @@ def __new__( seconds = sign * fsum( map( lambda n_u: float(n_u.group(1)) * cls.scale[n_u.group(3)], - re.finditer(r"([0-9]*(\.[0-9]*)?)([a-z]+)", seconds), + re.finditer(rf"([0-9]*(\.[0-9]*)?)({units_pattern})", seconds), ) ) except KeyError: diff --git a/tests/test_celtypes.py b/tests/test_celtypes.py index 4ac9207..582c4b9 100644 --- a/tests/test_celtypes.py +++ b/tests/test_celtypes.py @@ -409,6 +409,17 @@ def test_duration_type(): assert DurationType("-2m30s").getSeconds() == IntType(-150) with pytest.raises(ValueError): DurationType("-2w30z") + assert int(DurationType("1.5h").total_seconds()) == 5400 + assert DurationType("300ms").getMilliseconds() == IntType(300) + assert DurationType("2ms").total_seconds() == 0.002 + with pytest.raises(ValueError): + DurationType("300msec") + with pytest.raises(ValueError): + DurationType("2hours") + with pytest.raises(ValueError): + DurationType("15sec") + with pytest.raises(ValueError): + DurationType("2m30sx") def test_function_type():