CVE-2023-41039 (Python, published 2023-08-30T18:15Z)
Description: value: RestrictedPython is a restricted execution environment for Python to run untrusted code. Python's "format" functionality allows someone controlling the format string to "read" all objects accessible through recursive attribute lookup and subscription from objects he can access. This can lead to critical information disclosure. With `RestrictedPython`, the format functionality is available via the `format` and `format_map` methods of `str` (and `unicode`) (accessed either via the class or its instances) and via `string.Formatter`. All known versions of `RestrictedPython` are vulnerable. This issue has been addressed in commit `4134aedcff1` which has been included in the 5.4 and 6.2 releases. Users are advised to upgrade. There are no known workarounds for this vulnerability.


Severity: nan (CVSS v3 base score: 7.7)
Weakness: CWE-74 \u2014 Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
Repository: https://github.com/zopefoundation/RestrictedPython
Files changed:
CHANGES.rst
src/RestrictedPython/Guards.py
src/RestrictedPython/Utilities.py
tests/builtins/test_utilities.py
tests/test_Guards.py
tests/test_Utilities.py
Commit message: Merge pull request from GHSA-xjw2-6jm9-rf67

* fix information disclosure problems through the `format*` methods of the `str` class and its instances

* Suggestion from @icemac

Co-authored-by: Michael Howitz <mh@gocept.com>

* prevent access to `string.Formatter`

* fix syntax in `CHANGES.rst`

---------

Co-authored-by: Michael Howitz <mh@gocept.com>

Vulnerable code:
    if isinstance(object, str) and name == 'format':
            'Using format() on a %s is not safe.' % object.__class__.__name__)
utility_builtins['string'] = string
    assert utility_builtins['string'] is string
def test_Guards__safer_getattr__1():
    assert 'Using format() on a str is not safe.' == str(err.value)
UNICODE_DOT_FORMAT_DENIED = """\
a = u'Hello {}'
b = a.format(u'world')
def test_Guards__safer_getattr__2():
    """It prevents using the format method of a unicode.
        restricted_exec(UNICODE_DOT_FORMAT_DENIED, glb)
    assert 'Using format() on a str is not safe.' == str(err.value)

Fixed code:
- Fix information disclosure problems through
  Python's "format" functionality
  (``format`` and ``format_map`` methods on ``str`` and its instances,
  ``string.Formatter``).

    if name in ('format', 'format_map') and (
            isinstance(object, str) or
            (isinstance(object, type) and issubclass(object, str))):
            'Using the format*() methods of `str` is not safe')

class _AttributeDelegator:
    def __init__(self, mod, *excludes):
        """delegate attribute lookups outside *excludes* to module *mod*."""
        self.__mod = mod
        self.__excludes = excludes

    def __getattr__(self, attr):
        if attr in self.__excludes:
            raise NotImplementedError(
                f"{self.__mod.__name__}.{attr} is not safe")
        return getattr(self.__mod, attr)


utility_builtins['string'] = _AttributeDelegator(string, "Formatter")

    # we no longer provide access to ``string`` itself, only to
    # a restricted view of it
    assert utility_builtins['string'].__name__ == string.__name__
def test_Guards__safer_getattr__1a():
    assert 'Using the format*() methods of `str` is not safe' == str(err.value)
# contributed by Ward Theunisse
STRING_DOT_FORMAT_MAP_DENIED = """\
a = 'Hello {foo.__dict__}'
b = a.format_map({foo:str})
def test_Guards__safer_getattr__1b():
    """It prevents using the format method of a string.

    format() is considered harmful:
    http://lucumr.pocoo.org/2016/12/29/careful-with-str-format/
    """
    glb = {
        '__builtins__': safe_builtins,
    }
    with pytest.raises(NotImplementedError) as err:
        restricted_exec(STRING_DOT_FORMAT_MAP_DENIED, glb)
    assert 'Using the format*() methods of `str` is not safe' == str(err.value)


# contributed by Abhishek Govindarasu
STR_DOT_FORMAT_DENIED = """\
str.format('{0.__class__.__mro__[1]}', int)
"""


def test_Guards__safer_getattr__1c():
    """It prevents using the format method of a string.

    format() is considered harmful:
    http://lucumr.pocoo.org/2016/12/29/careful-with-str-format/
    """
    glb = {
        '__builtins__': safe_builtins,
    }
    with pytest.raises(NotImplementedError) as err:
        restricted_exec(STR_DOT_FORMAT_DENIED, glb)
    assert 'Using the format*() methods of `str` is not safe' == str(err.value)


STR_DOT_FORMAT_MAP_DENIED = """\
str.format_map('Hello {foo.__dict__}', {'foo':str})
"""


def test_Guards__safer_getattr__1d():
    """It prevents using the format method of a string.
        restricted_exec(STR_DOT_FORMAT_MAP_DENIED, glb)
    assert 'Using the format*() methods of `str` is not safe' == str(err.value)
import pytest

from RestrictedPython.Utilities import utility_builtins


def test_Utilities_string_Formatter():
    """Access to ``string.Formatter`` is denied."""
    string = utility_builtins["string"]
    # access successful in principle
    assert string.ascii_lowercase == 'abcdefghijklmnopqrstuvwxyz'
    with pytest.raises(NotImplementedError) as exc:
        string.Formatter
    assert 'string.Formatter is not safe' == str(exc.value)