diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 91243378dc0441..8684bdb8dfd5c6 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -2398,17 +2398,31 @@ def get_section(value): The caller should already have dealt with leading CFWS. """ + def is_accepted_digit(d): + # While only ASCII digits are allowed by the RFC, we accept any digit + # that can be converted to an int for backwards compatibility purposes. + # We don't use str.isdigit() as some Unicode digits are not convertible + # (e.g. superscript digits). + try: + int(d) + return True + except ValueError: + return False + section = Section() if not value or value[0] != '*': raise errors.HeaderParseError("Expected section but found {}".format( value)) section.append(ValueTerminal('*', 'section-marker')) value = value[1:] - if not value or not value[0].isdigit(): + if not value or not is_accepted_digit(value[0]): raise errors.HeaderParseError("Expected section number but " "found {}".format(value)) digits = '' - while value and value[0].isdigit(): + while value and is_accepted_digit(value[0]): + if not '0' <= value[0] <= '9': + section.defects.append(errors.InvalidHeaderDefect( + "section number has a non-ASCII digit {}".format(value[0]))) digits += value[0] value = value[1:] if digits[0] == '0' and digits != '0': diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py index 179e236ecdfd7f..2eaf73bad89afa 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -2982,6 +2982,21 @@ def mime_parameters_as_value(self, 'r*=\'a\'"', [('r', '"')], [errors.InvalidHeaderDefect]*2), + + # gh-87112: Only digits convertible to integers can be section numbers. + 'non_accepted_digit': ( + 'foo*0=bar; foo*²=baz', + ' foo="bar"', + 'foo*0=bar; foo*²=baz', + [('foo', 'bar')], + [errors.InvalidHeaderDefect]), + + 'non_ascii_digit_backwards_compatibility': ( + 'foo*0=bar; foo*߁=baz', # NKO digit '1' + ' foo="barbaz"', + 'foo*0=bar; foo*߁=baz', + [('foo', 'barbaz')], + [errors.InvalidHeaderDefect]), } @parameterize diff --git a/Misc/NEWS.d/next/Library/2025-07-20-17-57-39.gh-issue-87112.sKU2V8.rst b/Misc/NEWS.d/next/Library/2025-07-20-17-57-39.gh-issue-87112.sKU2V8.rst new file mode 100644 index 00000000000000..ba4e72de85e317 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-20-17-57-39.gh-issue-87112.sKU2V8.rst @@ -0,0 +1,2 @@ +Ensure that only digits convertible to integers are accepted as section number +in MIME header parameter.