VYPR
High severityNVD Advisory· Published Jul 11, 2023· Updated Nov 7, 2024

RestrictedPython vulnerable to arbitrary code execution via stack frame sandbox escape

CVE-2023-37271

Description

RestrictedPython fails to restrict stack frame access via generators, allowing sandbox escape and potential arbitrary code execution.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

RestrictedPython fails to restrict stack frame access via generators, allowing sandbox escape and potential arbitrary code execution.

Vulnerability

Analysis

RestrictedPython is a tool that defines a subset of Python to allow untrusted code execution in a trusted environment. Prior to versions 6.1 and 5.3, it did not properly check access to stack frames and their attributes [1]. Stack frames are accessible within generators and generator expressions, which are permitted in RestrictedPython. An attacker with access to a RestrictedPython environment can craft code that retrieves the current stack frame inside a generator and then traverse the stack beyond the RestrictedPython invocation boundary, escaping the sandbox [1][2].

Exploitation

To exploit this vulnerability, an attacker must have the ability to write and execute Python code within a RestrictedPython environment. This is typically a non-default configuration, for example in Zope or Plone deployments where administrators allow untrusted users to create or edit objects such as Script (Python), DTML Method, DTML Document, or Zope Page Template [1]. The attack does not require authentication beyond the ability to submit restricted code. By using generator expressions or generators, the attacker can access the gi_frame attribute and then walk the stack using f_back to reach frames outside the restricted execution context [2].

Impact

Successful exploitation allows an attacker to break out of the restricted sandbox and potentially execute arbitrary code in the Python interpreter [1]. This could lead to full compromise of the host application, including data exfiltration, privilege escalation, or further attacks on the underlying system.

Mitigation

The issue is fixed in RestrictedPython versions 6.1 and 5.3 [1]. The fix restricts access to attributes related to stack frames, tracebacks, code objects, generators, and coroutines, as defined in the INSPECT_ATTRIBUTES list in the transformer [2]. Users should upgrade to these versions or later. As a workaround, administrators can disable untrusted user access to the script editing features in Zope/Plone if upgrading is not immediate [1].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
RestrictedPythonPyPI
< 5.35.3
RestrictedPythonPyPI
>= 6.0a1.dev0, < 6.16.1
restrictedpythonPyPI
< 5.35.3

Affected products

2

Patches

3
f9ef13be3f38

- prepare release 5.3

2 files changed · +2 2
  • CHANGES.rst+1 1 modified
    @@ -1,7 +1,7 @@
     Changes
     =======
     
    -5.3 (unreleased)
    +5.3 (2023-07-08)
     ----------------
     
     - Restrict access to some attributes accessible via the ``inspect`` module.
    
  • setup.py+1 1 modified
    @@ -32,7 +32,7 @@ def read(*rnames):
     
     setup(
         name='RestrictedPython',
    -    version='5.3.dev0',
    +    version='5.3',
         url='https://github.com/zopefoundation/RestrictedPython',
         license='ZPL 2.1',
         description=(
    
311f2f7eee49

- prepare release 6.1

2 files changed · +2 2
  • CHANGES.rst+1 1 modified
    @@ -1,7 +1,7 @@
     Changes
     =======
     
    -6.1 (unreleased)
    +6.1 (2023-07-08)
     ----------------
     
     - Restrict access to some attributes accessible via the ``inspect`` module.
    
  • setup.py+1 1 modified
    @@ -32,7 +32,7 @@ def read(*rnames):
     
     setup(
         name='RestrictedPython',
    -    version='6.1.dev0',
    +    version='6.1',
         url='https://github.com/zopefoundation/RestrictedPython',
         license='ZPL 2.1',
         description=(
    
c8eca66ae490

Merge pull request from GHSA-wqc8-x2pr-7jqh

https://github.com/zopefoundation/restrictedpythonAlexander LoechelJul 8, 2023via ghsa
4 files changed · +99 0
  • CHANGES.rst+5 0 modified
    @@ -15,6 +15,11 @@ Features
     - Allow to use the package with Python 3.12 -- Caution: No security audit has
       been done so far.
     
    +Fixes
    ++++++
    +
    +- Restrict access to some attributes accessible via the ``inspect`` module.
    +
     
     6.0 (2022-11-03)
     ----------------
    
  • docs/contributing/index.rst+1 0 modified
    @@ -64,6 +64,7 @@ To do so:
         All AST Nodes without an explicit ``visit_<AST Node>`` method, are denied by default.
         So the usage of this expression and functionality is not allowed.
     
    +* Check the documentation for `inspect <https://docs.python.org/3/library/inspect.html>`_ and adjust the ``transformer.py:INSPECT_ATTRIBUTES`` list.
     * Add a corresponding changelog entry.
     * Additionally modify ``.meta.toml`` and run the ``meta/config`` script (for details see: https://github.com/mgedmin/check-python-versions) to update the following files:
     
    
  • src/RestrictedPython/transformer.py+33 0 modified
    @@ -63,6 +63,32 @@
         'breakpoint',
     ])
     
    +# inspect attributes. See also
    +# https://docs.python.org/3/library/inspect.html
    +INSPECT_ATTRIBUTES = frozenset([
    +    # traceback
    +    "tb_frame",
    +    "tb_next",
    +    # code
    +    "co_code",
    +    # frame
    +    "f_back",
    +    "f_builtins",
    +    "f_code",
    +    "f_globals",
    +    "f_locals",
    +    "f_trace",
    +    # generator
    +    "gi_frame",
    +    "gi_code",
    +    "gi_yieldfrom",
    +    # coroutine
    +    "cr_await",
    +    "cr_frame",
    +    "cr_code",
    +    "cr_origin",
    +])
    +
     
     # When new ast nodes are generated they have no 'lineno', 'end_lineno',
     # 'col_offset' and 'end_col_offset'. This function copies these fields from the
    @@ -844,6 +870,13 @@ def visit_Attribute(self, node):
                     '"{name}" is an invalid attribute name because it ends '
                     'with "__roles__".'.format(name=node.attr))
     
    +        if node.attr in INSPECT_ATTRIBUTES:
    +            self.error(
    +                node,
    +                f'"{node.attr}" is a restricted name,'
    +                ' that is forbidden to access in RestrictedPython.',
    +            )
    +
             if isinstance(node.ctx, ast.Load):
                 node = self.node_contents_visit(node)
                 new_node = ast.Call(
    
  • tests/transformer/test_inspect.py+60 0 added
    @@ -0,0 +1,60 @@
    +from RestrictedPython import compile_restricted_exec
    +
    +
    +def test_get_inspect_frame_on_generator():
    +    source_code = """
    +generator = (statement.gi_frame for _ in (1,))
    +generator_element = [elem for elem in generator][0]
    +
    +"""
    +    result = compile_restricted_exec(source_code)
    +    assert result.errors == (
    +        'Line 2: "gi_frame" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +    )
    +
    +
    +def test_get_inspect_frame_back_on_generator():
    +    source_code = """
    +generator = (statement.gi_frame.f_back.f_back for _ in (1,))
    +generator_element = [elem for elem in generator][0]
    +
    +"""
    +    result = compile_restricted_exec(source_code)
    +    assert result.errors == (
    +        'Line 2: "f_back" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +        'Line 2: "f_back" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +        'Line 2: "gi_frame" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +    )
    +
    +
    +def test_call_inspect_frame_on_generator():
    +    source_code = """
    +generator = None
    +frame = None
    +
    +def test():
    +    global generator, frame
    +    frame = g.gi_frame.f_back.f_back
    +    yield frame
    +
    +generator = test()
    +generator.send(None)
    +os = frame.f_builtins.get('__import__')('os')
    +
    +result = os.listdir('/')
    +"""
    +    result = compile_restricted_exec(source_code)
    +    assert result.errors == (
    +        'Line 7: "f_back" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +        'Line 7: "f_back" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +        'Line 7: "gi_frame" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +        'Line 12: "f_builtins" is a restricted name, '
    +        'that is forbidden to access in RestrictedPython.',
    +    )
    

Vulnerability mechanics

Root cause

"RestrictedPython does not restrict access to stack frames and their attributes, allowing a generator to walk the stack beyond the sandbox boundary."

Attack vector

An attacker with the ability to write Python code inside a RestrictedPython environment can craft a generator or generator expression that accesses the current stack frame. By walking the stack frame chain, the attacker can escape the RestrictedPython sandbox boundary and reach the unrestricted Python interpreter. This allows arbitrary code execution outside the sandbox. The attack requires that the administrator has enabled untrusted users to create or edit objects such as ``Script (Python)``, ``DTML Method``, ``DTML Document``, or ``Zope Page Template``, which is a non-default configuration [CWE-913].

Affected code

The vulnerability lies in RestrictedPython's failure to restrict access to stack frames and their attributes. Stack frames are accessible within generators and generator expressions, which are permitted inside the sandbox. The patch restricts access to attributes accessible via the ``inspect`` module, but the exact code paths are not detailed in the supplied patches.

What the fix does

The fix restricts access to attributes accessible via the ``inspect`` module, which is the vector used to obtain stack frames. By blocking these attributes, attackers can no longer use the ``inspect`` module to retrieve the current stack frame from within a generator. The patches in versions 5.3 [patch_id=1640687] and 6.1 [patch_id=1640686] both apply the same restriction. The underlying commit [patch_id=1707204] implements the actual code change that closes the sandbox escape.

Preconditions

  • configThe administrator must allow untrusted users to create or edit Python script objects (Script (Python), DTML Method, DTML Document, or Zope Page Template) in a RestrictedPython environment.
  • inputThe attacker must have the ability to write and execute Python code within the RestrictedPython sandbox.

Generated on May 23, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.