Skip to content

Commit

Permalink
Merge pull request from GHSA-8xv7-89vj-q48c
Browse files Browse the repository at this point in the history
* fix information disclosure via `format_map`

* Fix CHANGES.rst according to review

Co-authored-by: Jens Vagelpohl <jens@plyp.com>

* Add CVE

---------

Co-authored-by: Jens Vagelpohl <jens@plyp.com>
Co-authored-by: Michael Howitz <mh@gocept.com>
  • Loading branch information
3 people committed Sep 4, 2023
1 parent f9ae588 commit 6bc3269
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -6,6 +6,9 @@ For changes before version 3.0, see ``HISTORY.rst``.
6.2 (unreleased)
----------------

- Fix information disclosure through ``str.format_map``.
(CVE-2023-41050)


6.1 (2023-05-22)
----------------
Expand Down
2 changes: 2 additions & 0 deletions src/AccessControl/__init__.py
Expand Up @@ -14,6 +14,7 @@
# This has to happen early so things get initialized properly
from AccessControl.Implementation import setImplementation
from AccessControl.safe_formatter import safe_format
from AccessControl.safe_formatter import safe_format_map
from AccessControl.SecurityInfo import ACCESS_NONE
from AccessControl.SecurityInfo import ACCESS_PRIVATE
from AccessControl.SecurityInfo import ACCESS_PUBLIC
Expand Down Expand Up @@ -44,6 +45,7 @@
# That one needs special handling to avoid access to attributes.
rules = {m: True for m in dir(str) if not m.startswith('_')}
rules['format'] = safe_format
rules['format_map'] = safe_format_map
allow_type(str, rules)

zodbupdate_decode_dict = {
Expand Down
8 changes: 8 additions & 0 deletions src/AccessControl/safe_formatter.py
Expand Up @@ -72,7 +72,15 @@ def safe_format(self, *args, **kwargs):
kwargs = _MagicFormatMapping(args, kwargs)
return self.vformat(self.value, args, kwargs)

def safe_format_map(self, kw):
kwargs = _MagicFormatMapping((), kw)
return self.vformat(self.value, (), kwargs)


def safe_format(inst, method):
"""Use our SafeFormatter that uses guarded_getattr for attribute access."""
return SafeFormatter(inst).safe_format


def safe_format_map(inst, method):
return SafeFormatter(inst).safe_format_map
22 changes: 22 additions & 0 deletions src/AccessControl/tests/test_safe_formatter.py
Expand Up @@ -202,3 +202,25 @@ def test_prevents_bad_unicode_formatting_key(self):
self.assertRaises(Unauthorized,
SafeFormatter('{0[1]}').safe_format,
folder)

def test_format_map(self):
from AccessControl.safe_formatter import SafeFormatter

# Accessing basic Python types in a basic Python list is fine.
foo = list(['bar'])
self.assertEqual(SafeFormatter('{foo[0]}')
.safe_format_map(dict(foo=foo)),
'bar')
# But for non-basic items or non-basic lists, we want run checks.
folder = self._create_folder_with_mixed_contents()
# We can get the public items just fine:
self.assertEqual(SafeFormatter('{foo[0]}')
.safe_format_map(dict(foo=folder)),
'<Item public1>')
self.assertEqual(SafeFormatter('{foo[2]}')
.safe_format_map(dict(foo=folder)),
'<Item public2>')
# But not the private item:
self.assertRaises(Unauthorized,
SafeFormatter('{foo[1]}').safe_format_map,
dict(foo=folder))

0 comments on commit 6bc3269

Please sign in to comment.