Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd4df3c5

Browse files
brianschubertbitdancermedmundsambv
authored
[3.9]gh-80222: Fix email address header folding with long quoted-string (GH-122753) (GH-129111) (GH-132371)
Email generators using email.policy.default could incorrectly omit thequote ('"') characters from a quoted-string during header refolding,leading to invalid address headers and enabling header spoofing. Thischange restores the quote characters on a bare-quoted-string as theheader is refolded, and escapes backslash and quote chars in the string.(cherry picked from commit5aaf416)(cherry picked from commita4ef689)Co-authored-by: R. David Murray <rdmurray@bitdance.com>Co-authored-by: Mike Edmunds <medmunds@gmail.com>Co-authored-by: Łukasz Langa <lukasz@langa.pl>
1 parent558e27a commitd4df3c5

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

‎Lib/email/_header_value_parser.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,16 @@
9595
NLSET= {'\n','\r'}
9696
SPECIALSNL=SPECIALS|NLSET
9797

98+
99+
defmake_quoted_pairs(value):
100+
"""Escape dquote and backslash for use within a quoted-string."""
101+
returnstr(value).replace('\\','\\\\').replace('"','\\"')
102+
103+
98104
defquote_string(value):
99-
return'"'+str(value).replace('\\','\\\\').replace('"',r'\"')+'"'
105+
escaped=make_quoted_pairs(value)
106+
returnf'"{escaped}"'
107+
100108

101109
# Match a RFC 2047 word, looks like =?utf-8?q?someword?=
102110
rfc2047_matcher=re.compile(r'''
@@ -2848,6 +2856,15 @@ def _refold_parse_tree(parse_tree, *, policy):
28482856
ifnothasattr(part,'encode'):
28492857
# It's not a terminal, try folding the subparts.
28502858
newparts=list(part)
2859+
ifpart.token_type=='bare-quoted-string':
2860+
# To fold a quoted string we need to create a list of terminal
2861+
# tokens that will render the leading and trailing quotes
2862+
# and use quoted pairs in the value as appropriate.
2863+
newparts= (
2864+
[ValueTerminal('"','ptext')]+
2865+
[ValueTerminal(make_quoted_pairs(p),'ptext')
2866+
forpinnewparts]+
2867+
[ValueTerminal('"','ptext')])
28512868
ifnotpart.as_ew_allowed:
28522869
wrap_as_ew_blocked+=1
28532870
newparts.append(end_ew_not_allowed)

‎Lib/test/test_email/test__header_value_parser.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2946,6 +2946,33 @@ def test_address_list_with_unicode_names_in_quotes(self):
29462946
'=?utf-8?q?H=C3=BCbsch?= Kaktus <beautiful@example.com>,\n'
29472947
' =?utf-8?q?bei=C3=9Ft_bei=C3=9Ft?= <biter@example.com>\n')
29482948

2949+
deftest_address_list_with_specials_in_long_quoted_string(self):
2950+
# Regression for gh-80222.
2951+
policy=self.policy.clone(max_line_length=40)
2952+
cases= [
2953+
# (to, folded)
2954+
('"Exfiltrator <spy@example.org> (unclosed comment?" <to@example.com>',
2955+
'"Exfiltrator <spy@example.org> (unclosed\n'
2956+
' comment?" <to@example.com>\n'),
2957+
('"Escaped\\" chars\\\\ in quoted-string stay escaped" <to@example.com>',
2958+
'"Escaped\\" chars\\\\ in quoted-string\n'
2959+
' stay escaped" <to@example.com>\n'),
2960+
('This long display name does not need quotes <to@example.com>',
2961+
'This long display name does not need\n'
2962+
' quotes <to@example.com>\n'),
2963+
('"Quotes are not required but are retained here" <to@example.com>',
2964+
'"Quotes are not required but are\n'
2965+
' retained here" <to@example.com>\n'),
2966+
('"A quoted-string, it can be a valid local-part"@example.com',
2967+
'"A quoted-string, it can be a valid\n'
2968+
' local-part"@example.com\n'),
2969+
('"local-part-with-specials@but-no-fws.cannot-fold"@example.com',
2970+
'"local-part-with-specials@but-no-fws.cannot-fold"@example.com\n'),
2971+
]
2972+
for (to,folded)incases:
2973+
withself.subTest(to=to):
2974+
self._test(parser.get_address_list(to)[0],folded,policy=policy)
2975+
29492976
deftest_address_list_with_specials_in_encoded_word(self):
29502977
# An encoded-word parsed from a structured header must remain
29512978
# encoded when it contains specials. Regression for gh-121284.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Fix bug in the folding of quoted strings when flattening an email message using
2+
a modern email policy. Previously when a quoted string was folded so that
3+
it spanned more than one line, the surrounding quotes and internal escapes
4+
would be omitted. This could theoretically be used to spoof header lines
5+
using a carefully constructed quoted string if the resulting rendered email
6+
was transmitted or re-parsed.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp