CVE-2021-21360 (Python)

Products.GenericSetup is a mini-framework for expressing the configured state of a Zope Site as a set of filesystem artifacts. In Products.GenericSetup before version 2.1.1 there is an information disclosure vulnerability - anonymous visitors may view log and snapshot files generated by the Generic Setup Tool. The problem has been fixed in version 2.1.1. Depending on how you have installed Products.GenericSetup, you should change the buildout version pin to 2.1.1 and re-run the buildout, or if you used pip simply do pip install `"Products.GenericSetup>=2.1.1"`.

Weakness:
CWE-200: name: Exposure of Sensitive Information to an Unauthorized Actor
description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.

Repository: https://github.com/zopefoundation/Products.GenericSetup

Vulnerable code:
file_path: src/Products/GenericSetup/context.py
snippet:     def writeDataFile(self, filename, text, content_type, subdir=None):
        """ See IExportContext.
        """
        if subdir is not None:
            filename = '/'.join((subdir, filename))

        sep = filename.rfind('/')
        if sep != -1:
            subdir = filename[:sep]
            filename = filename[sep+1:]

        if six.PY2 and isinstance(text, six.text_type):
            encoding = self.getEncoding() or 'utf-8'
            text = text.encode(encoding)

        folder = self._ensureSnapshotsFolder(subdir)

        # MISSING: switch on content_type
        ob = self._createObjectByType(filename, text, content_type)
        folder._setObject(str(filename), ob)  # No Unicode IDs!

file_path: src/Products/GenericSetup/context.py
snippet:     def _ensureSnapshotsFolder(self, subdir=None):
        """ Ensure that the appropriate snapshot folder exists.
        """
        path = ['snapshots', self._snapshot_id]

        if subdir is not None:
            path.extend(subdir.split('/'))

        current = self._tool

        for element in path:

            if element not in current.objectIds():
                # No Unicode IDs!
                current._setObject(str(element), Folder(element))

            current = current._getOb(element)

        return current

Fixed code:
file_path: src/Products/GenericSetup/context.py
snippet:     def writeDataFile(self, filename, text, content_type, subdir=None):
        """ See IExportContext.
        """
        if subdir is not None:
            filename = '/'.join((subdir, filename))

        sep = filename.rfind('/')
        if sep != -1:
            subdir = filename[:sep]
            filename = filename[sep+1:]

        if six.PY2 and isinstance(text, six.text_type):
            encoding = self.getEncoding() or 'utf-8'
            text = text.encode(encoding)

        folder = self._ensureSnapshotsFolder(subdir)

        # MISSING: switch on content_type
        ob = self._createObjectByType(filename, text, content_type)
        folder._setObject(str(filename), ob)  # No Unicode IDs!
        # Tighten the View permission on the new object.
        # Only the owner and Manager users may view the log.
        # file_ob = self._getOb(name)
        ob.manage_permission(view, ('Manager', 'Owner'), 0)

file_path: src/Products/GenericSetup/context.py
snippet:     def _ensureSnapshotsFolder(self, subdir=None):
        """ Ensure that the appropriate snapshot folder exists.
        """
        path = ['snapshots', self._snapshot_id]

        if subdir is not None:
            path.extend(subdir.split('/'))

        current = self._tool

        for element in path:

            if element not in current.objectIds():
                # No Unicode IDs!
                current._setObject(str(element), Folder(element))
                current = current._getOb(element)
                current.manage_permission(view, ('Manager', 'Owner'), 0)
            else:
                current = current._getOb(element)

        return current