Skip to content

Commit

Permalink
Merge pull request from GHSA-4hpj-8rhv-9x87
Browse files Browse the repository at this point in the history
Improve handling of PortalFolder filter input.
  • Loading branch information
dataflake committed Jul 3, 2023
2 parents 1fa289c + abdf4cd commit 40f03f4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 12 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Products.CMFCore Changelog
3.2 (unreleased)
----------------

- Nothing changed yet.
- Improve handling of PortalFolder filter input.


3.1 (2023-06-01)
Expand Down
25 changes: 14 additions & 11 deletions src/Products/CMFCore/PortalFolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
""" PortalFolder: CMF-enabled Folder objects.
"""

import marshal
import json
import re

from AccessControl.class_init import InitializeClass
Expand Down Expand Up @@ -235,23 +235,26 @@ def encodeFolderFilter(self, REQUEST):
"""
Parse cookie string for using variables in dtml.
"""
filter = {}
folder_filter = {}
for key, value in REQUEST.items():
if key[:10] == 'filter_by_':
filter[key[10:]] = value
encoded = base64_encode(marshal.dumps(filter))
encoded = ''.join(encoded.split('\n'))
folder_filter[key[10:]] = value
encoded = base64_encode(json.dumps(folder_filter).encode())
encoded = b''.join(encoded.split(b'\n'))
return encoded

@security.public
def decodeFolderFilter(self, encoded):
""" Parse cookie string for using variables in dtml.
This is a public method and the input is not under our control.
To prevent a DOS this method will refuse to decode data that seems
conspicuously large.
"""
Parse cookie string for using variables in dtml.
"""
filter = {}
if encoded:
filter.update(marshal.loads(base64_decode(encoded)))
return filter
folder_filter = {}
if encoded and len(encoded) < 1000:
folder_filter.update(json.loads(base64_decode(encoded)))
return folder_filter

def content_type(self):
"""
Expand Down
32 changes: 32 additions & 0 deletions src/Products/CMFCore/tests/test_PortalFolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,38 @@ def test_interfaces(self):

verifyClass(IOrderedContainer, self._getTargetClass())

def test_FolderFilter(self):
folder = self._getTargetClass()('test_id')

# No filter
request = {}
encoded_filter = folder.encodeFolderFilter(request)
self.assertEqual(folder.decodeFolderFilter(encoded_filter), {})

# Simple filter
request = {'filter_by_id': 'foobar'}
encoded_filter = folder.encodeFolderFilter(request)
self.assertEqual(folder.decodeFolderFilter(encoded_filter),
{'id': 'foobar'})

# Multiple filters
request = {'filter_by_id': 'foobar',
'filter_by_title': 'baz'}
encoded_filter = folder.encodeFolderFilter(request)
self.assertEqual(folder.decodeFolderFilter(encoded_filter),
{'id': 'foobar', 'title': 'baz'})

# Non-filter request values are ignored
request = {'filter_by_id': 'foobar', 'somekey': 'somevalue'}
encoded_filter = folder.encodeFolderFilter(request)
self.assertEqual(folder.decodeFolderFilter(encoded_filter),
{'id': 'foobar'})

# Conspicuously large input values to the decode operation
# are ignored to prevent a DOS
encoded_filter = 'x' * 2000
self.assertEqual(folder.decodeFolderFilter(encoded_filter), {})


class PortalFolderSecurityTests(SecurityTest):

Expand Down

0 comments on commit 40f03f4

Please sign in to comment.