VYPR
Moderate severityNVD Advisory· Published Sep 6, 2023· Updated Sep 26, 2024

Information disclosure through Python's "format" functionality in Zope AccessControl

CVE-2023-41050

Description

AccessControl provides a general security framework for use in Zope. Python's "format" functionality allows someone controlling the format string to "read" objects accessible (recursively) via attribute access and subscription from accessible objects. Those attribute accesses and subscriptions use Python's full blown getattr and getitem, not the policy restricted AccessControl variants _getattr_ and _getitem_. This can lead to critical information disclosure. AccessControl already provides a safe variant for str.format and denies access to string.Formatter. However, str.format_map is still unsafe. Affected are all users who allow untrusted users to create AccessControl controlled Python code and execute it. A fix has been introduced in versions 4.4, 5.8 and 6.2. Users are advised to upgrade. There are no known workarounds for this vulnerability.

AI Insight

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

A format string vulnerability in Zope's AccessControl allows authentication bypass through str.format_map calls.

Vulnerability

Overview

CVE-2023-41050 is a critical information disclosure vulnerability discovered in the AccessControl security framework for Zope [1]. The root cause lies in how AccessControl handles Python's str.format_map() method. Python's format functionality allows someone controlling the format string to read objects accessible through attribute access and subscription from accessible objects. These calls use Python's full getattr and getitem, bypassing the policy-restricted _getattr_ and _getitem_ variants that AccessControl normally enforces [2].

Exploitation

Vector

The vulnerability affects all users who allow untrusted users to create and execute AccessControl-controlled Python code [1]. While AccessControl already provides a safe variant for str.format and denies access to string.Formatter, the str.format_map method remained unprotected [3]. An attacker who can influence format strings can leverage str.format_map to traverse the object graph, accessing attributes and items recursively without respecting AccessControl's security policies.

Impact

Successful exploitation leads to critical information disclosure. An attacker can read sensitive data from objects that would normally be restricted by AccessControl's security policies. This includes any data reachable via attribute access or subscription from accessible objects, potentially exposing confidential configuration, user data, or system internals [1][3].

Mitigation

A fix has been introduced in AccessControl versions 4.4, 5.8, and 6.2 [1][3]. The patch adds a safe_format_map method to the SafeFormatter class, which uses the policy-restricted access controls [4]. Users are strongly advised to upgrade to these patched versions. There are no known workarounds for this vulnerability [1][3].

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
AccessControlPyPI
< 4.44.4
ZopePyPI
< 4.8.94.8.9
AccessControlPyPI
>= 5.0, < 5.85.8
AccessControlPyPI
>= 6.0, < 6.26.2
ZopePyPI
>= 5.0.0, < 5.8.45.8.4

Affected products

3

Patches

1
6bc32692e0d4

Merge pull request from GHSA-8xv7-89vj-q48c

https://github.com/zopefoundation/AccessControlDieter MaurerSep 4, 2023via ghsa
4 files changed · +35 0
  • CHANGES.rst+3 0 modified
    @@ -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)
     ----------------
    
  • src/AccessControl/__init__.py+2 0 modified
    @@ -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
    @@ -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 = {
    
  • src/AccessControl/safe_formatter.py+8 0 modified
    @@ -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
    
  • src/AccessControl/tests/test_safe_formatter.py+22 0 modified
    @@ -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))
    

Vulnerability mechanics

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

References

4

News mentions

0

No linked articles in our index yet.