diff options
author | Mike Edmunds <medmunds@gmail.com> | 2025-01-19 00:50:52 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-19 00:50:52 (GMT) |
commit | 5aaf41685834901e4ed0a40f4c055b92991a0bb5 (patch) | |
tree | 82b4dd8aa0c225c2db38853fb8d1592d6db9f2cd /Lib/email/_header_value_parser.py | |
parent | 61b35f74aa4a6ac606635e245147ff3658628d99 (diff) | |
download | cpython-5aaf41685834901e4ed0a40f4c055b92991a0bb5.zip cpython-5aaf41685834901e4ed0a40f4c055b92991a0bb5.tar.gz cpython-5aaf41685834901e4ed0a40f4c055b92991a0bb5.tar.bz2 |
gh-80222: Fix email address header folding with long quoted-string (#122753)
Email generators using email.policy.default could incorrectly omit the
quote ('"') characters from a quoted-string during header refolding,
leading to invalid address headers and enabling header spoofing. This
change restores the quote characters on a bare-quoted-string as the
header is refolded, and escapes backslash and quote chars in the string.
Diffstat (limited to 'Lib/email/_header_value_parser.py')
-rw-r--r-- | Lib/email/_header_value_parser.py | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index ec2215a..3d845c0 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -95,8 +95,16 @@ EXTENDED_ATTRIBUTE_ENDS = ATTRIBUTE_ENDS - set('%') NLSET = {'\n', '\r'} SPECIALSNL = SPECIALS | NLSET + +def make_quoted_pairs(value): + """Escape dquote and backslash for use within a quoted-string.""" + return str(value).replace('\\', '\\\\').replace('"', '\\"') + + def quote_string(value): - return '"'+str(value).replace('\\', '\\\\').replace('"', r'\"')+'"' + escaped = make_quoted_pairs(value) + return f'"{escaped}"' + # Match a RFC 2047 word, looks like =?utf-8?q?someword?= rfc2047_matcher = re.compile(r''' @@ -2905,6 +2913,15 @@ def _refold_parse_tree(parse_tree, *, policy): if not hasattr(part, 'encode'): # It's not a terminal, try folding the subparts. newparts = list(part) + if part.token_type == 'bare-quoted-string': + # To fold a quoted string we need to create a list of terminal + # tokens that will render the leading and trailing quotes + # and use quoted pairs in the value as appropriate. + newparts = ( + [ValueTerminal('"', 'ptext')] + + [ValueTerminal(make_quoted_pairs(p), 'ptext') + for p in newparts] + + [ValueTerminal('"', 'ptext')]) if not part.as_ew_allowed: wrap_as_ew_blocked += 1 newparts.append(end_ew_not_allowed) |