VYPR
Moderate severityOSV Advisory· Published Dec 14, 2022· Updated Aug 3, 2024

collective.dms.basecontent column.py renderCell cross site scripting

CVE-2022-4495

Description

A vulnerability, which was classified as problematic, has been found in collective.dms.basecontent up to 1.6. This issue affects the function renderCell of the file src/collective/dms/basecontent/browser/column.py. The manipulation leads to cross site scripting. The attack may be initiated remotely. Upgrading to version 1.7 is able to address this issue. The name of the patch is 6c4d616fcc771822a14ebae5e23f3f6d96d134bd. It is recommended to upgrade the affected component. The identifier VDB-215813 was assigned to this vulnerability.

AI Insight

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

A stored XSS vulnerability in collective.dms.basecontent <=1.6 allows remote attackers to inject arbitrary web script via the renderCell function in column.py.

Vulnerability

CVE-2022-4495 is a stored cross-site scripting (XSS) vulnerability found in the renderCell function of the file src/collective/dms/basecontent/browser/column.py in the collective.dms.basecontent Python package up to and including version 1.6 [1][2]. The root cause is the lack of HTML escaping for user-controllable values such as user full names and group titles when rendering cells in a table column [2]. The commit 6c4d616 introduces proper escaping by wrapping these outputs with the escape() function, confirming the flaw [2].

Exploitation

The attack may be initiated remotely, and the vulnerable function processes data obtained from Plone member and group objects (e.g., via getProperty('fullname', None)) [2]. An attacker who can influence a Plone user's full name or a group's title—for example, through user registration or group management—can inject arbitrary HTML or JavaScript code. When the renderCell method is invoked to display the list of principals associated with a DMS content item, the injected payload is rendered unsanitized in the browser of any user viewing the affected table, including administrators [2]. No special authentication is required for some attack paths if user profile fields are editable by low-privileged accounts.

Impact

Successful exploitation allows an attacker to execute arbitrary script in the context of a victim's browser session. This can lead to session hijacking, credential theft, defacement, or redirection to malicious sites. Because the package is used within Plone CMS environments, the impact extends to any site relying on collective.dms.basecontent for document management functionality.

Mitigation

The vulnerability is fixed in version 1.7 of collective.dms.basecontent [1][4]. Users are strongly advised to upgrade to this version. The fix applies standard HTML escaping (from html import escape) to both user full names and group titles before they are concatenated into the cell output [2]. No workarounds other than upgrading have been documented; however, administrators may consider restricting the ability to edit user profile fields or group titles as an interim measure.

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
collective.dms.basecontentPyPI
< 1.71.7

Affected products

1

Patches

1
6c4d616fcc77

Updated columns to work with z3c.table 2.2. Escaped rendering special caracters to avoid xss

3 files changed · +30 19
  • CHANGES.rst+2 2 modified
    @@ -4,8 +4,8 @@ Changelog
     1.7 (unreleased)
     ----------------
     
    -- Nothing changed yet.
    -
    +- Updated columns to work with z3c.table 2.2. Escaped rendering special caracters to avoid xss.
    +  [sgeulette]
     
     1.6 (2021-04-20)
     ----------------
    
  • setup.py+2 1 modified
    @@ -49,6 +49,7 @@
             'five.grok',
             'collective.documentviewer',
             'dexterity.localrolesfield',
    +        'future',
             'plone.api',
             'plone.app.dexterity',
             'plone.directives.form',
    @@ -59,7 +60,7 @@
             'plone.formwidget.contenttree',
             'plone.principalsource',
             'collective.z3cform.chosen',
    -        'z3c.table',
    +        'z3c.table>=2.2',
         ],
         extras_require={
             'test': ['plone.app.testing',
    
  • src/collective/dms/basecontent/browser/column.py+26 16 modified
    @@ -1,19 +1,22 @@
    -import os.path
    -import Missing
    -from Acquisition import aq_base
     from AccessControl import getSecurityManager
    -from Products.CMFCore.utils import getToolByName
    +from Acquisition import aq_base
    +from collective.dms.basecontent import _
     from five import grok
    +from html import escape
    +from Products.CMFCore.utils import getToolByName
    +from Products.CMFCore.WorkflowCore import WorkflowException
    +from Products.CMFPlone.utils import safe_unicode
     from z3c.table import interfaces
     from zope.component import getMultiAdapter
    -from zope.i18nmessageid import MessageFactory
     from zope.i18n import translate
    -import z3c.table.table
    -import z3c.table.column
    -from Products.CMFCore.WorkflowCore import WorkflowException
    +from zope.i18nmessageid import MessageFactory
    +
    +import Missing
    +import os.path
     import plone.api
    +import z3c.table.column
    +import z3c.table.table
     
    -from collective.dms.basecontent import _
     
     PMF = MessageFactory('plone')
     
    @@ -74,11 +77,11 @@ def renderCell(self, item):
             for principal_id in value:
                 user = mtool.getMemberById(principal_id)
                 if user is not None:
    -                principals.append(user.getProperty('fullname', None) or user.getId())
    +                principals.append(escape(user.getProperty('fullname', None)) or user.getId())
                 else:
                     group = gtool.getGroupById(principal_id)
                     if group is not None:
    -                    principals.append(group.getProperty('title', None) or group.getId())
    +                    principals.append(escape(group.getProperty('title', None)) or group.getId())
     
             return ', '.join(principals).decode('utf-8')
     
    @@ -92,6 +95,16 @@ def getLinkURL(self, item):
                 return '%s/%s' % (item.getURL(), self.linkName)
             return item.getURL()
     
    +    def renderCell(self, item):
    +        # setup a tag
    +        return '<a href="%s"%s%s%s>%s</a>' % (
    +            self.getLinkURL(item),  # originally escaped
    +            self.getLinkTarget(item),
    +            self.getLinkCSS(item),
    +            self.getLinkTitle(item),
    +            self.getLinkContent(item),  # originally escaped
    +        )
    +
     
     class TitleColumn(LinkColumn):
         grok.baseclass()
    @@ -100,17 +113,14 @@ class TitleColumn(LinkColumn):
     
         def getLinkContent(self, item):
             title = get_value(item, 'Title')
    -        if isinstance(title, unicode):
    -            return title
    -        else:
    -            return unicode(title, 'utf-8', 'ignore')
    +        return escape(safe_unicode(title))
     
     
     class IconColumn(LinkColumn):
         grok.baseclass()
     
         def getLinkContent(self, item):
    -        content = super(IconColumn, self).getLinkContent(item)
    +        content = super(IconColumn, self).getLinkContent(item)  # escaped
             return u"""<img title="%s" src="%s" />""" % (
                 content,
                 '%s/%s' % (self.table.portal_url, self.iconName))
    

Vulnerability mechanics

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

References

6

News mentions

0

No linked articles in our index yet.