From 70f89be700df0d5f08ef696252c88741f8414060 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Thu, 4 Aug 2022 14:45:38 -0600 Subject: [PATCH] fix redos-able regex and add poc code to tests (#182) --- .../_utils/structured_data/validation.py | 2 +- newsfragments/178.bugfix.rst | 1 + tests/core/test_structured_data_signing.py | 24 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 newsfragments/178.bugfix.rst diff --git a/eth_account/_utils/structured_data/validation.py b/eth_account/_utils/structured_data/validation.py index e5b6fa24..fcb9197d 100644 --- a/eth_account/_utils/structured_data/validation.py +++ b/eth_account/_utils/structured_data/validation.py @@ -6,7 +6,7 @@ # Regexes IDENTIFIER_REGEX = r"^[a-zA-Z_$][a-zA-Z_$0-9]*$" -TYPE_REGEX = r"^[a-zA-Z_$][a-zA-Z_$0-9]*(\[([1-9]\d*)*\])*$" +TYPE_REGEX = r"^[a-zA-Z_$][a-zA-Z_$0-9]*(\[([1-9]\d*\b)*\])*$" def validate_has_attribute(attr_name, dict_data): diff --git a/newsfragments/178.bugfix.rst b/newsfragments/178.bugfix.rst new file mode 100644 index 00000000..24adc6c3 --- /dev/null +++ b/newsfragments/178.bugfix.rst @@ -0,0 +1 @@ +fix DoS-able regex pattern diff --git a/tests/core/test_structured_data_signing.py b/tests/core/test_structured_data_signing.py index d09df2b2..a136393b 100644 --- a/tests/core/test_structured_data_signing.py +++ b/tests/core/test_structured_data_signing.py @@ -1,6 +1,7 @@ import json import pytest import re +import time from eth_abi.exceptions import ( ABITypeError, @@ -199,6 +200,29 @@ def test_type_regex(type, valid): assert re.match(TYPE_REGEX, type) is None +def test_type_regex_for_redos(): + start = time.time() + # len 30 string is long enough to cause > 1 second delay if the regex is bad + long = '1' * 30 + invalid_structured_data_string = f"""{{ + "types": {{ + "EIP712Domain": [ + {{"name": "aaaa", "type": "$[{long}0"}}, + {{"name": "version", "type": "string"}}, + {{"name": "chainId", "type": "uint256"}}, + {{"name": "verifyingContract", "type": "address"}} + ] + }} + }}""" + + with pytest.raises(re.error, match="unterminated character set at position 15"): + with pytest.raises(ValidationError, match=f"Invalid Type `$[{long}0` in `EIP712Domain`"): + load_and_validate_structured_message(invalid_structured_data_string) + + done = time.time() - start + assert done < 1 + + def test_structured_data_invalid_identifier_filtered_by_regex(): invalid_structured_data_string = open( "tests/fixtures/invalid_struct_identifier_message.json"