diff --git a/CHANGES.rst b/CHANGES.rst index e9dc507..68d7998 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,8 @@ Changes it as ``getattr`` implementation. Such use should now follow the same policy and give the same level of protection as direct attribute access in an environment based on ``RestrictedPython``'s ``safe_builtints``. +- Prevent information leakage via ``AttributeError.obj`` + and the ``string`` module. 7.2 (2024-08-02) diff --git a/src/RestrictedPython/Utilities.py b/src/RestrictedPython/Utilities.py index 10188e9..26d73d1 100644 --- a/src/RestrictedPython/Utilities.py +++ b/src/RestrictedPython/Utilities.py @@ -29,7 +29,11 @@ def __getattr__(self, attr): if attr in self.__excludes: raise NotImplementedError( f"{self.__mod.__name__}.{attr} is not safe") - return getattr(self.__mod, attr) + try: + return getattr(self.__mod, attr) + except AttributeError as e: + e.obj = self + raise utility_builtins['string'] = _AttributeDelegator(string, "Formatter") diff --git a/tests/builtins/test_utilities.py b/tests/builtins/test_utilities.py index 1ad26d7..0d3992e 100644 --- a/tests/builtins/test_utilities.py +++ b/tests/builtins/test_utilities.py @@ -7,8 +7,17 @@ def test_string_in_utility_builtins(): from RestrictedPython.Utilities import utility_builtins # we no longer provide access to ``string`` itself, only to - # a restricted view of it - assert utility_builtins['string'].__name__ == string.__name__ + # a restricted view of it (``rstring``) + rstring = utility_builtins['string'] + assert rstring.__name__ == string.__name__ + + # ensure it does not provide access to ``string`` via + # ``AttributeError.obj`` + try: + rstring.unexisting_attribute + except AttributeError as e: + assert e.obj is rstring + def test_math_in_utility_builtins():