CVE-2021-32633 (Python, published 2021-05-21T14:15Z)
Description: value: Zope is an open-source web application server. In Zope versions prior to 4.6 and 5.2, users can access untrusted modules indirectly through Python modules that are available for direct use. By default, only users with the Manager role can add or edit Zope Page Templates through the web, but sites that allow untrusted users to add/edit Zope Page Templates through the web are at risk from this vulnerability. The problem has been fixed in Zope 5.2 and 4.6. As a workaround, a site administrator can restrict adding/editing Zope Page Templates through the web using the standard Zope user/role permission mechanisms. Untrusted users should not be assigned the Zope Manager role and adding/editing Zope Page Templates through the web should be restricted to trusted users only.
Severity: MEDIUM (CVSS v3 base score: 8.8)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/zopefoundation/Zope
Files changed:
CHANGES.rst
src/Products/PageTemplates/Expressions.py
src/Products/PageTemplates/expression.py
src/Products/PageTemplates/tests/input/CheckPathTraverse.html
src/Products/PageTemplates/tests/output/CheckPathTraverse.html
src/Products/PageTemplates/tests/testChameleonTalesExpressions.py
src/Products/PageTemplates/tests/testExpressions.py
src/Products/PageTemplates/tests/testHTMLTests.py
Commit message: Merge pull request from GHSA-5pr9-v234-jw36

* - Prevent traversal to names starting with ``_`` in TAL expressions

* - include the expressions module

* - simplify test

* - lint fix

* - add DeprecationWarnings for traversal to `_`

* Update src/Products/PageTemplates/tests/testChameleonTalesExpressions.py

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

* - add missing import

* - added tests for the ``traverse`` method fix

* - change control flow

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

Vulnerable code:
                base = getattr(base, cls.traverseMethod)(name)
        self.assertEqual(ec.evaluate('d/_'), 'under')

Fixed code:
- Prevent traversal to names starting with ``_`` in TAL expressions
  and fix path expressions for the ``chameleon.tales`` expression engine.

import warnings

        if name == '_':
            warnings.warn('Traversing to the name `_` is deprecated '
                          'and will be removed in Zope 6.',
                          DeprecationWarning)
        elif name.startswith('_'):
            raise NotFound(name)

import warnings

            if name == '_':
                warnings.warn('Traversing to the name `_` is deprecated '
                              'and will be removed in Zope 6.',
                              DeprecationWarning)
            elif name.startswith('_'):
                raise NotFound(name)

                base = getattr(base, cls.traverse_method)(name)
<html>
<body>
   <div tal:content="context/laf"></div>
</body>
</html>
<html>
<body>
   <div>ok</div>
</body>
</html>
import unittest


    @unittest.skip('The test in the base class relies on a Zope context with'
                   ' the "random" module available in expressions')
    def test_underscore_traversal(self):
        pass
import warnings
from zExceptions import NotFound
        # Traversing to the name `_` will raise a DeprecationWarning
        # because it will go away in Zope 6.
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')
            self.assertEqual(ec.evaluate('d/_'), 'under')
    def test_underscore_traversal(self):
        # Prevent traversal to names starting with an underscore (_)
        ec = self._makeContext()

        with self.assertRaises(NotFound):
            ec.evaluate("context/__class__")

        with self.assertRaises(NotFound):
            ec.evaluate("nocall: random/_itertools/repeat")

        with self.assertRaises(NotFound):
            ec.evaluate("random/_itertools/repeat/foobar")

from zExceptions import NotFound
    def testPathTraverse(self):
        # need to perform this test with a "real" folder
        from OFS.Folder import Folder
        f = self.folder
        self.folder = Folder()
        self.folder.t, self.folder.laf = f.t, f.laf
        self.folder.laf.write('ok')
        self.assert_expected(self.folder.t, 'CheckPathTraverse.html')


    def test_underscore_traversal(self):
        t = self.folder.t

        t.write('<p tal:define="p context/__class__" />')
        with self.assertRaises(NotFound):
            t()

        t.write('<p tal:define="p nocall: random/_itertools/repeat"/>')
        with self.assertRaises(NotFound):
            t()

        t.write('<p tal:content="random/_itertools/repeat/foobar"/>')
        with self.assertRaises(NotFound):
            t()