diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ba3d34b..46011a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 7.8.6 - 2026-02-09 + +fix: limit collections scanning in code variables + # 7.8.5 - 2026-02-09 fix: further optimize code variables pattern matching diff --git a/posthog/exception_utils.py b/posthog/exception_utils.py index 4cec07e4..4cdee77d 100644 --- a/posthog/exception_utils.py +++ b/posthog/exception_utils.py @@ -66,6 +66,7 @@ CODE_VARIABLES_TOO_LONG_VALUE = "$$_posthog_value_too_long_$$" _MAX_VALUE_LENGTH_FOR_PATTERN_MATCH = 5_000 +_MAX_COLLECTION_ITEMS_TO_SCAN = 100 _REGEX_METACHARACTERS = frozenset(r"\.^$*+?{}[]|()") DEFAULT_TOTAL_VARIABLES_SIZE_LIMIT = 20 * 1024 @@ -991,6 +992,8 @@ def _mask_sensitive_data(value, compiled_mask, _seen=None): _seen.add(obj_id) if isinstance(value, dict): + if len(value) > _MAX_COLLECTION_ITEMS_TO_SCAN: + return CODE_VARIABLES_TOO_LONG_VALUE result = {} for k, v in value.items(): key_str = str(k) if not isinstance(k, str) else k @@ -1002,6 +1005,8 @@ def _mask_sensitive_data(value, compiled_mask, _seen=None): result[k] = _mask_sensitive_data(v, compiled_mask, _seen) return result elif isinstance(value, (list, tuple)): + if len(value) > _MAX_COLLECTION_ITEMS_TO_SCAN: + return CODE_VARIABLES_TOO_LONG_VALUE masked_items = [ _mask_sensitive_data(item, compiled_mask, _seen) for item in value ] diff --git a/posthog/test/test_exception_capture.py b/posthog/test/test_exception_capture.py index a90a000e..3d2f8d08 100644 --- a/posthog/test/test_exception_capture.py +++ b/posthog/test/test_exception_capture.py @@ -639,3 +639,51 @@ def test_compile_patterns_fast_path_and_regex_fallback(): # No match assert _pattern_matches("safe_var", mixed) is False + + +def test_mask_sensitive_data_large_dict_replaced(): + from posthog.exception_utils import ( + CODE_VARIABLES_TOO_LONG_VALUE, + _compile_patterns, + _mask_sensitive_data, + ) + + compiled_mask = _compile_patterns([r"(?i)password"]) + + large_dict = {f"key_{i}": f"value_{i}" for i in range(300)} + + result = _mask_sensitive_data(large_dict, compiled_mask) + + assert result == CODE_VARIABLES_TOO_LONG_VALUE + + +def test_mask_sensitive_data_large_list_replaced(): + from posthog.exception_utils import ( + CODE_VARIABLES_TOO_LONG_VALUE, + _compile_patterns, + _mask_sensitive_data, + ) + + compiled_mask = _compile_patterns([r"(?i)password"]) + + large_list = [f"item_{i}" for i in range(300)] + + result = _mask_sensitive_data(large_list, compiled_mask) + + assert result == CODE_VARIABLES_TOO_LONG_VALUE + + +def test_mask_sensitive_data_large_tuple_replaced(): + from posthog.exception_utils import ( + CODE_VARIABLES_TOO_LONG_VALUE, + _compile_patterns, + _mask_sensitive_data, + ) + + compiled_mask = _compile_patterns([r"(?i)password"]) + + large_tuple = tuple(f"item_{i}" for i in range(300)) + + result = _mask_sensitive_data(large_tuple, compiled_mask) + + assert result == CODE_VARIABLES_TOO_LONG_VALUE diff --git a/posthog/version.py b/posthog/version.py index 9581625a..08a3bb39 100644 --- a/posthog/version.py +++ b/posthog/version.py @@ -1,4 +1,4 @@ -VERSION = "7.8.5" +VERSION = "7.8.6" if __name__ == "__main__": print(VERSION, end="") # noqa: T201