• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / AccessControl / 6069496693

04 Sep 2023 05:28AM UTC coverage: 81.124% (+0.05%) from 81.072%
6069496693

push

github

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

* 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>

933 of 1457 branches covered (0.0%)

Branch coverage included in aggregate %.

14 of 15 new or added lines in 3 files covered. (93.33%)

4998 of 5854 relevant lines covered (85.38%)

5.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.78
/src/AccessControl/safe_formatter.py
1
import string
6✔
2
from collections.abc import Mapping
6✔
3

4
import _string
6✔
5

6
from AccessControl.ZopeGuards import guarded_getattr
6✔
7
from AccessControl.ZopeGuards import guarded_getitem
6✔
8

9

10
def formatter_field_name_split(field_name):
6✔
11
    return _string.formatter_field_name_split(field_name)
6✔
12

13

14
class _MagicFormatMapping(Mapping):
6✔
15
    """Pulled from Jinja2.
16

17
    This class implements a dummy wrapper to fix a bug in the Python
18
    standard library for string formatting.
19

20
    See http://bugs.python.org/issue13598 for information about why
21
    this is necessary.
22
    """
23

24
    def __init__(self, args, kwargs):
6✔
25
        self._args = args
6✔
26
        self._kwargs = kwargs
6✔
27
        self._last_index = 0
6✔
28

29
    def __getitem__(self, key):
6✔
30
        if key == '':
6!
31
            idx = self._last_index
×
32
            self._last_index += 1
×
33
            try:
×
34
                return self._args[idx]
×
35
            except LookupError:
×
36
                pass
×
37
            key = str(idx)
×
38
        return self._kwargs[key]
6✔
39

40
    def __iter__(self):
6✔
41
        return iter(self._kwargs)
×
42

43
    def __len__(self):
6✔
44
        return len(self._kwargs)
×
45

46

47
class SafeFormatter(string.Formatter):
6✔
48
    """Formatter using guarded access."""
49

50
    def __init__(self, value):
6✔
51
        self.value = value
6✔
52
        super().__init__()
6✔
53

54
    def get_field(self, field_name, args, kwargs):
6✔
55
        """Get the field value using guarded methods."""
56
        first, rest = formatter_field_name_split(field_name)
6✔
57

58
        obj = self.get_value(first, args, kwargs)
6✔
59

60
        # loop through the rest of the field_name, doing
61
        #  getattr or getitem as needed
62
        for is_attr, i in rest:
6✔
63
            if is_attr:
6✔
64
                obj = guarded_getattr(obj, i)
6✔
65
            else:
66
                obj = guarded_getitem(obj, i)
6✔
67

68
        return obj, first
6✔
69

70
    def safe_format(self, *args, **kwargs):
6✔
71
        """Safe variant of `format` method."""
72
        kwargs = _MagicFormatMapping(args, kwargs)
6✔
73
        return self.vformat(self.value, args, kwargs)
6✔
74

75
    def safe_format_map(self, kw):
6✔
76
        kwargs = _MagicFormatMapping((), kw)
6✔
77
        return self.vformat(self.value, (), kwargs)
6✔
78

79

80
def safe_format(inst, method):
6✔
81
    """Use our SafeFormatter that uses guarded_getattr for attribute access."""
82
    return SafeFormatter(inst).safe_format
×
83

84

85
def safe_format_map(inst, method):
6✔
NEW
86
    return SafeFormatter(inst).safe_format_map
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc