Skip to content

Commit 362793e

Browse files
committed
pythongh-106669: Revert "pythongh-102988: Detect email address parsing errors and return empty tuple to indicate the parsing error (old API) (python#105127)"
This reverts commit 18dfbd0. See python#106669.
1 parent 025995f commit 362793e

File tree

5 files changed

+10
-172
lines changed

5 files changed

+10
-172
lines changed

Doc/library/email.utils.rst

+1-25
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,6 @@ of the new API.
6565
*email address* parts. Returns a tuple of that information, unless the parse
6666
fails, in which case a 2-tuple of ``('', '')`` is returned.
6767

68-
.. versionchanged:: 3.12
69-
For security reasons, addresses that were ambiguous and could parse into
70-
multiple different addresses now cause ``('', '')`` to be returned
71-
instead of only one of the *potential* addresses.
72-
7368

7469
.. function:: formataddr(pair, charset='utf-8')
7570

@@ -92,7 +87,7 @@ of the new API.
9287
This method returns a list of 2-tuples of the form returned by ``parseaddr()``.
9388
*fieldvalues* is a sequence of header field values as might be returned by
9489
:meth:`Message.get_all <email.message.Message.get_all>`. Here's a simple
95-
example that gets all the recipients of a message:
90+
example that gets all the recipients of a message::
9691

9792
from email.utils import getaddresses
9893

@@ -102,25 +97,6 @@ of the new API.
10297
resent_ccs = msg.get_all('resent-cc', [])
10398
all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs)
10499

105-
When parsing fails for a single fieldvalue, a 2-tuple of ``('', '')``
106-
is returned in its place. Other errors in parsing the list of
107-
addresses such as a fieldvalue seemingly parsing into multiple
108-
addresses may result in a list containing a single empty 2-tuple
109-
``[('', '')]`` being returned rather than returning potentially
110-
invalid output.
111-
112-
Example malformed input parsing:
113-
114-
.. doctest::
115-
116-
>>> from email.utils import getaddresses
117-
118-
[('', '')]
119-
120-
.. versionchanged:: 3.12
121-
The 2-tuple of ``('', '')`` in the returned values when parsing
122-
fails were added as to address a security issue.
123-
124100

125101
.. function:: parsedate(date)
126102

Doc/whatsnew/3.12.rst

-8
Original file line numberDiff line numberDiff line change
@@ -570,14 +570,6 @@ dis
570570
:data:`~dis.hasarg` collection instead.
571571
(Contributed by Irit Katriel in :gh:`94216`.)
572572

573-
email
574-
-----
575-
576-
* :func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now return
577-
``('', '')`` 2-tuples in more situations where invalid email addresses are
578-
encountered instead of potentially inaccurate values.
579-
(Contributed by Thomas Dwyer for :gh:`102988` to ameliorate CVE-2023-27043.)
580-
581573
fractions
582574
---------
583575

Lib/email/utils.py

+6-57
Original file line numberDiff line numberDiff line change
@@ -106,54 +106,12 @@ def formataddr(pair, charset='utf-8'):
106106
return address
107107

108108

109-
def _pre_parse_validation(email_header_fields):
110-
accepted_values = []
111-
for v in email_header_fields:
112-
s = v.replace('\\(', '').replace('\\)', '')
113-
if s.count('(') != s.count(')'):
114-
v = "('', '')"
115-
accepted_values.append(v)
116-
117-
return accepted_values
118-
119-
120-
def _post_parse_validation(parsed_email_header_tuples):
121-
accepted_values = []
122-
# The parser would have parsed a correctly formatted domain-literal
123-
# The existence of an [ after parsing indicates a parsing failure
124-
for v in parsed_email_header_tuples:
125-
if '[' in v[1]:
126-
v = ('', '')
127-
accepted_values.append(v)
128-
129-
return accepted_values
130-
131109

132110
def getaddresses(fieldvalues):
133-
"""Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue.
134-
135-
When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in
136-
its place.
137-
138-
If the resulting list of parsed address is not the same as the number of
139-
fieldvalues in the input list a parsing error has occurred. A list
140-
containing a single empty 2-tuple [('', '')] is returned in its place.
141-
This is done to avoid invalid output.
142-
"""
143-
fieldvalues = [str(v) for v in fieldvalues]
144-
fieldvalues = _pre_parse_validation(fieldvalues)
145-
all = COMMASPACE.join(v for v in fieldvalues)
111+
"""Return a list of (REALNAME, EMAIL) for each fieldvalue."""
112+
all = COMMASPACE.join(str(v) for v in fieldvalues)
146113
a = _AddressList(all)
147-
result = _post_parse_validation(a.addresslist)
148-
149-
n = 0
150-
for v in fieldvalues:
151-
n += v.count(',') + 1
152-
153-
if len(result) != n:
154-
return [('', '')]
155-
156-
return result
114+
return a.addresslist
157115

158116

159117
def _format_timetuple_and_zone(timetuple, zone):
@@ -254,18 +212,9 @@ def parseaddr(addr):
254212
Return a tuple of realname and email address, unless the parse fails, in
255213
which case return a 2-tuple of ('', '').
256214
"""
257-
if isinstance(addr, list):
258-
addr = addr[0]
259-
260-
if not isinstance(addr, str):
261-
return ('', '')
262-
263-
addr = _pre_parse_validation([addr])[0]
264-
addrs = _post_parse_validation(_AddressList(addr).addresslist)
265-
266-
if not addrs or len(addrs) > 1:
267-
return ('', '')
268-
215+
addrs = _AddressList(addr).addresslist
216+
if not addrs:
217+
return '', ''
269218
return addrs[0]
270219

271220

Lib/test/test_email/test_email.py

+3-78
Original file line numberDiff line numberDiff line change
@@ -3319,90 +3319,15 @@ def test_getaddresses(self):
33193319
[('Al Person', '[email protected]'),
33203320
('Bud Person', '[email protected]')])
33213321

3322-
def test_getaddresses_parsing_errors(self):
3323-
"""Test for parsing errors from CVE-2023-27043"""
3324-
eq = self.assertEqual
3325-
eq(utils.getaddresses(['[email protected](<[email protected]>']),
3326-
[('', '')])
3327-
eq(utils.getaddresses(['[email protected])<[email protected]>']),
3328-
[('', '')])
3329-
eq(utils.getaddresses(['[email protected]<<[email protected]>']),
3330-
[('', '')])
3331-
eq(utils.getaddresses(['[email protected]><[email protected]>']),
3332-
[('', '')])
3333-
eq(utils.getaddresses(['[email protected]@<[email protected]>']),
3334-
[('', '')])
3335-
eq(utils.getaddresses(['[email protected],<[email protected]>']),
3336-
3337-
eq(utils.getaddresses(['[email protected];<[email protected]>']),
3338-
[('', '')])
3339-
eq(utils.getaddresses(['[email protected]:<[email protected]>']),
3340-
[('', '')])
3341-
eq(utils.getaddresses(['[email protected].<[email protected]>']),
3342-
[('', '')])
3343-
eq(utils.getaddresses(['[email protected]"<[email protected]>']),
3344-
[('', '')])
3345-
eq(utils.getaddresses(['[email protected][<[email protected]>']),
3346-
[('', '')])
3347-
eq(utils.getaddresses(['[email protected]]<[email protected]>']),
3348-
[('', '')])
3349-
3350-
def test_parseaddr_parsing_errors(self):
3351-
"""Test for parsing errors from CVE-2023-27043"""
3352-
eq = self.assertEqual
3353-
eq(utils.parseaddr(['[email protected](<[email protected]>']),
3354-
('', ''))
3355-
eq(utils.parseaddr(['[email protected])<[email protected]>']),
3356-
('', ''))
3357-
eq(utils.parseaddr(['[email protected]<<[email protected]>']),
3358-
('', ''))
3359-
eq(utils.parseaddr(['[email protected]><[email protected]>']),
3360-
('', ''))
3361-
eq(utils.parseaddr(['[email protected]@<[email protected]>']),
3362-
('', ''))
3363-
eq(utils.parseaddr(['[email protected],<[email protected]>']),
3364-
('', ''))
3365-
eq(utils.parseaddr(['[email protected];<[email protected]>']),
3366-
('', ''))
3367-
eq(utils.parseaddr(['[email protected]:<[email protected]>']),
3368-
('', ''))
3369-
eq(utils.parseaddr(['[email protected].<[email protected]>']),
3370-
('', ''))
3371-
eq(utils.parseaddr(['[email protected]"<[email protected]>']),
3372-
('', ''))
3373-
eq(utils.parseaddr(['[email protected][<[email protected]>']),
3374-
('', ''))
3375-
eq(utils.parseaddr(['[email protected]]<[email protected]>']),
3376-
('', ''))
3377-
33783322
def test_getaddresses_nasty(self):
33793323
eq = self.assertEqual
33803324
eq(utils.getaddresses(['foo: ;']), [('', '')])
3381-
eq(utils.getaddresses(['[]*-- =~$']), [('', '')])
3325+
eq(utils.getaddresses(
3326+
['[]*-- =~$']),
3327+
[('', ''), ('', ''), ('', '*--')])
33823328
eq(utils.getaddresses(
33833329
['foo: ;', '"Jason R. Mastaler" <[email protected]>']),
33843330
[('', ''), ('Jason R. Mastaler', '[email protected]')])
3385-
eq(utils.getaddresses(
3386-
[r'Pete(A nice \) chap) <pete(his account)@silly.test(his host)>']),
3387-
[('Pete (A nice ) chap his account his host)', '[email protected]')])
3388-
eq(utils.getaddresses(
3389-
['(Empty list)(start)Undisclosed recipients :(nobody(I know))']),
3390-
[('', '')])
3391-
eq(utils.getaddresses(
3392-
['Mary <@machine.tld:[email protected]>, , jdoe@test . example']),
3393-
[('Mary', '[email protected]'), ('', ''), ('', '[email protected]')])
3394-
eq(utils.getaddresses(
3395-
['John Doe <jdoe@machine(comment). example>']),
3396-
[('John Doe (comment)', '[email protected]')])
3397-
eq(utils.getaddresses(
3398-
['"Mary Smith: Personal Account" <[email protected]>']),
3399-
[('Mary Smith: Personal Account', '[email protected]')])
3400-
eq(utils.getaddresses(
3401-
['Undisclosed recipients:;']),
3402-
[('', '')])
3403-
eq(utils.getaddresses(
3404-
[r'<[email protected]>, "Giant; \"Big\" Box" <[email protected]>']),
3405-
[('', '[email protected]'), ('Giant; "Big" Box', '[email protected]')])
34063331

34073332
def test_getaddresses_embedded_comment(self):
34083333
"""Test proper handling of a nested comment"""

Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst

-4
This file was deleted.

0 commit comments

Comments
 (0)