| defdecode_header(header): |
| """Decode a message header value without converting charset. |
| |
| For historical reasons, this function may return either: |
| |
| 1. A list of length 1 containing a pair (str, None). |
| 2. A list of (bytes, charset) pairs containing each of the decoded |
| parts of the header. Charset is None for non-encoded parts of the header, |
| otherwise a lower-case string containing the name of the character set |
| specified in the encoded string. |
| |
| header may be a string that may or may not contain RFC2047 encoded words, |
| or it may be a Header object. |
| |
| An email.errors.HeaderParseError may be raised when certain decoding error |
| occurs (e.g. a base64 decoding exception). |
| |
| This function exists for backwards compatibility only. For new code, we |
| recommend using email.headerregistry.HeaderRegistry instead. |
| """ |
| # If it is a Header object, we can just return the encoded chunks. |
| ifhasattr(header, '_chunks'): |
| return [(_charset._encode(string, str(charset)), str(charset)) |
| forstring, charsetinheader._chunks] |
| # If no encoding, just return the header with no charset. |
| ifnotecre.search(header): |
| return [(header, None)] |
| # First step is to parse all the encoded parts into triplets of the form |
| # (encoded_string, encoding, charset). For unencoded strings, the last |
| # two parts will be None. |
| words= [] |
| forlineinheader.splitlines(): |
| parts=ecre.split(line) |
| first=True |
| whileparts: |
| unencoded=parts.pop(0) |
| iffirst: |
| unencoded=unencoded.lstrip() |
| first=False |
| ifunencoded: |
| words.append((unencoded, None, None)) |
| ifparts: |
| charset=parts.pop(0).lower() |
| encoding=parts.pop(0).lower() |
| encoded=parts.pop(0) |
| words.append((encoded, encoding, charset)) |
| # Now loop over words and remove words that consist of whitespace |
| # between two encoded strings. |
| droplist= [] |
| forn, winenumerate(words): |
| ifn>1andw[1] andwords[n-2][1] andwords[n-1][0].isspace(): |
| droplist.append(n-1) |
| fordinreversed(droplist): |
| delwords[d] |
| |
| # The next step is to decode each encoded word by applying the reverse |
| # base64 or quopri transformation. decoded_words is now a list of the |
| # form (decoded_word, charset). |
| decoded_words= [] |
| forencoded_string, encoding, charsetinwords: |
| ifencodingisNone: |
| # This is an unencoded word. |
| decoded_words.append((encoded_string, charset)) |
| elifencoding=='q': |
| word=email.quoprimime.header_decode(encoded_string) |
| decoded_words.append((word, charset)) |
| elifencoding=='b': |
| paderr=len(encoded_string) %4# Postel's law: add missing padding |
| ifpaderr: |
| encoded_string+='==='[:4-paderr] |
| try: |
| word=email.base64mime.decode(encoded_string) |
| exceptbinascii.Error: |
| raiseHeaderParseError('Base64 decoding error') |
| else: |
| decoded_words.append((word, charset)) |
| else: |
| raiseAssertionError('Unexpected encoding: '+encoding) |
| # Now convert all words to bytes and collapse consecutive runs of |
| # similarly encoded words. |
| collapsed= [] |
| last_word=last_charset=None |
| forword, charsetindecoded_words: |
| ifisinstance(word, str): |
| word=bytes(word, 'raw-unicode-escape') |
| iflast_wordisNone: |
| last_word=word |
| last_charset=charset |
| elifcharset!=last_charset: |
| collapsed.append((last_word, last_charset)) |
| last_word=word |
| last_charset=charset |
| eliflast_charsetisNone: |
| last_word+=BSPACE+word |
| else: |
| last_word+=word |
| collapsed.append((last_word, last_charset)) |
| returncollapsed |
Bug Description:
A series of simple quadratic complexity vulnerabilities has been identified in the
emailpackage. After confirmation by CPython's security team, these low-threat DOS vulnerabilities can be fixed with community assistance.Vulnerability Locations (All Fixed):
cpython/Lib/email/message.py
Line 73 in 5ab66a8
2.
cpython/Lib/email/_header_value_parser.py
Line 1424 in 5ab66a8
3.
cpython/Lib/email/_header_value_parser.py
Line 1506 in 5ab66a8
4.
cpython/Lib/email/_header_value_parser.py
Line 1688 in 5ab66a8
5.
cpython/Lib/email/_header_value_parser.py
Line 1697 in 5ab66a8
6.
cpython/Lib/email/_header_value_parser.py
Line 1847 in 5ab66a8
7.
cpython/Lib/email/_header_value_parser.py
Line 2200 in 5ab66a8
8.
cpython/Lib/email/_header_value_parser.py
Line 2231 in 5ab66a8
9.
cpython/Lib/email/_header_value_parser.py
Line 2260 in 5ab66a8
10.
cpython/Lib/email/_header_value_parser.py
Line 2411 in 5ab66a8
11.
cpython/Lib/email/_header_value_parser.py
Line 2570 in 5ab66a8
12.
cpython/Lib/email/_header_value_parser.py
Line 2642 in 5ab66a8
13.
cpython/Lib/email/_header_value_parser.py
Line 2762 in 5ab66a8
14.
cpython/Lib/email/_header_value_parser.py
Line 2965 in 5ab66a8
Below are the newly identified DoS risk points in the
emailmodule, added on 2026/01/23, updated from #144133:cpython/Lib/email/_header_value_parser.py
Line 2838 in e66597d
cpython/Lib/email/_header_value_parser.py
Line 3076 in e66597d
cpython/Lib/email/message.py
Line 879 in e66597d
cpython/Lib/email/_parseaddr.py
Line 527 in 5ab66a8
cpython/Lib/email/_parseaddr.py
Line 551 in 5ab66a8
cpython/Lib/email/_header_value_parser.py
Line 319 in 6181b69
cpython/Lib/email/_header_value_parser.py
Line 354 in 6181b69
more:
TokenList.all_defects:
cpython/Lib/email/_header_value_parser.py
Lines 152 to 154 in 6181b69
AddressList.mailboxes:
cpython/Lib/email/_header_value_parser.py
Lines 313 to 316 in 6181b69
get_encoded_word:
cpython/Lib/email/_header_value_parser.py
Lines 1074 to 1121 in 6181b69
get_unstructured:
cpython/Lib/email/_header_value_parser.py
Lines 1123 to 1188 in 6181b69
get_bare_quoted_string:
cpython/Lib/email/_header_value_parser.py
Lines 1238 to 1279 in 6181b69
get_comment:
cpython/Lib/email/_header_value_parser.py
Lines 1281 to 1304 in 6181b69
get_dot_atom_text:
cpython/Lib/email/_header_value_parser.py
Lines 1364 to 1381 in 6181b69
get_dot_atom:
cpython/Lib/email/_header_value_parser.py
Lines 1383 to 1406 in 6181b69
get_word:
cpython/Lib/email/_header_value_parser.py
Lines 1408 to 1440 in 6181b69
get_local_part:
cpython/Lib/email/_header_value_parser.py
Lines 1480 to 1517 in 6181b69
get_domain:
cpython/Lib/email/_header_value_parser.py
Lines 1638 to 1674 in 6181b69
get_addr_spec:
cpython/Lib/email/_header_value_parser.py
Lines 1676 to 1690 in 6181b69
get_angle_addr:
cpython/Lib/email/_header_value_parser.py
Lines 1735 to 1779 in 6181b69
get_display_name:
cpython/Lib/email/_header_value_parser.py
Lines 1781 to 1793 in 6181b69
get_name_addr:
cpython/Lib/email/_header_value_parser.py
Lines 1796 to 1830 in 6181b69
get_mailbox:
cpython/Lib/email/_header_value_parser.py
Lines 1832 to 1851 in 6181b69
get_mailbox_list:
cpython/Lib/email/_header_value_parser.py
Lines 1871 to 1925 in 6181b69
get_group_list:
cpython/Lib/email/_header_value_parser.py
Lines 1928 to 1963 in 6181b69
get_group:
cpython/Lib/email/_header_value_parser.py
Lines 1965 to 1993 in 6181b69
get_address:
cpython/Lib/email/_header_value_parser.py
Lines 1995 to 2022 in 6181b69
get_address_list:
cpython/Lib/email/_header_value_parser.py
Lines 2024 to 2076 in 6181b69
get_msg_id:
cpython/Lib/email/_header_value_parser.py
Lines 2101 to 2167 in 6181b69
parse_message_id:
cpython/Lib/email/_header_value_parser.py
Lines 2170 to 2188 in 6181b69
parse_mime_parameters:
cpython/Lib/email/_header_value_parser.py
Lines 2627 to 2677 in 6181b69
AddrlistClass.getaddress:
cpython/Lib/email/_parseaddr.py
Lines 274 to 331 in 6181b69
Charset.header_encode_lines:
cpython/Lib/email/charset.py
Lines 293 to 352 in 6181b69
decode_header:
cpython/Lib/email/header.py
Lines 59 to 156 in 6181b69
Header._normalize:
cpython/Lib/email/header.py
Lines 398 to 414 in 6181b69
Message.set_param:
cpython/Lib/email/message.py
Lines 745 to 794 in 6181b69
Message.del_param:
cpython/Lib/email/message.py
Lines 796 to 816 in 6181b69
Repair Status:
_header_value_parser.py[WIP] #134947).Common Information:
Linked PRs
_header_value_parser.py[WIP] #134947email.message._parseparam#136072email.message._parseparam(GH-136072) #140827email.message._parseparam(GH-136072) #140828email.message._parseparam(GH-136072) #140829email.message._parseparam(GH-136072) #140830email.message._parseparam(GH-136072) #140831email.message._parseparam(GH-136072) #140832