New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr() #111116
Conversation
|
@gpshead @serhiy-storchaka @bitdancer @warsaw: Would you mind to review this security fix? See issue gh-102988 for the context. This PR is a copy of PR #108250 but I added strict=True parameter, so it's possible to get the old behavior. I added tests on both modes, strict=True and strict=False. |
My colleague Lumir Balhar @frenzymadness ran an impact check of PR #108250 on Fedora: in short, there is no impact, the test suite of all Python packages (in Fedora) pass with the change. While there were some build errors, they were unrelated to the email issue. For details, see https://copr.fedorainfracloud.org/coprs/lbalhar/email-CVE/builds/ COPR which as more than 4300 builds. Now with an additional strict parameter, if there is any impacted project, at least there is a way to "opt out". |
|
@tdwyer: Would you mind to review my change, to see if I preserved your work correctly? (code and tests) |
|
I think that we should backport the change to all branches accepting security fixes. Problem: the change refer to version numbers, which as |
|
@ambv @SethMichaelLarson: Would you mind to review this PR? |
|
Why is this a separate PR from #108250? |
Doc/whatsnew/3.13.rst
Outdated
| @@ -165,7 +165,7 @@ email | |||
| encountered instead of potentially inaccurate values. Add optional *strict* | |||
| parameter to these two functions: use ``strict=False`` to get the old | |||
| behavior, accept malformed inputs. | |||
| (Contributed by Thomas Dwyer for :gh:`102988` to ameliorate CVE-2023-27043 | |||
| (Contributed by Thomas Dwyer for :gh:`102988` to improve the CVE-2023-27043 | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL a new word.
Lib/email/utils.py
Outdated
| @@ -42,6 +42,8 @@ | |||
|
|
|||
| specialsre = re.compile(r'[][\\()<>@,:;".]') | |||
| escapesre = re.compile(r'[\\"]') | |||
| realname_comma_re = re.compile(r'"[^"]*,[^"]*"') | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| realname_comma_re = re.compile(r'"[^"]*,[^"]*"') | |
| realname_comma_re = re.compile(r'"[^",]*+,[^"]*+"') |
It is faster. But I am not sure that the use of such regex is correct.
Lib/email/utils.py
Outdated
| def _pre_parse_validation(email_header_fields): | ||
| accepted_values = [] | ||
| for v in email_header_fields: | ||
| s = v.replace('\\(', '').replace('\\)', '') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what if that backslash was already escaped with a backslash? For example \\) or \\\\).
I'm not the author of the other PR. I copied the other PR and added strict parameter. |
|
I'm not the author of this PR and I was able to make commits to it. |
I don't feel comfortable to make significant change of a PR without asking the author. I prefer to create a separated PR and ask for review. |
|
Is this behavior a bug or a feature? I don't know how |
Oh. getaddresses() expects a sequence, not a string :-) |
|
Except of The latest major change was done in... 1997 with commit be7c45e
The latest minor change was done in 2019 to fix CVE-2019-16056: commit 8cb65d1 of issue #78336. |
Oh, realname_comma_re replaces |
|
Email addresses have multiple standards:
|
The problem is that Red Hat Security Team has requirements for CVE depending on their severity. This one was qualified as Moderate severity which means short time to provide a fix: https://access.redhat.com/security/cve/cve-2023-27043 Well, I can try to argue with them to reduce the severity and so relax the urgency of a fix 😁 |
test_email is far from being complete, I cannot promise this change to be bug free. I can only show with the CI that it pass the current test_email test suite. Tests were added on "real names containing a comma". And a few more tests on edge cases discovered during the review. |
That is entirely Red Hat's issue. Red Hat has the tools to make its own decisions about backporting, backwards compatibility, and defaults -- and often uses them in this kind of situation, because its policies typical users are different from CPython's.
What sells it to me is that we can add a heavy API later -- we'll “just 1�7 need to figure out what strict=True maps to.
+1, merging it as a bugfix, but delaying backports to make fixes/rollbacks easier, makes sense to me. |
|
I'm fine with making the change in Python 3.13, wait feedback on a few Python 3.13 releases and then decide for the backports.
The issue has the security tag, should it be removed? Also, a CVE was assigned to it, before Python became a CNA.
Does someone known if there is a third party PyPI module with a good implementation of the email RFC? |
1�7.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
|
I don't mind the CVE on this one, even if I'm not convinced I would have filed one. We did clearly have buggy behavior in our library. We can't meaningfully undo the CVE existing anyways - I don't think this is worth filing a disputed claim over. I think it is fine to tag things as security issues even if we aren't backporting it or are holding off on deciding if we should backport it. We've done that on some other non-severe security/bug changes in the past (which aren't in my mind right now). I'll probably be applying a backport to our 3.11 runtime at work as well. :) As far as I'm concerned, that just increases testing to be confident we can do it in CPython's patch releases - if we encountered any issues as a result, I'd pipe up on the issue or file a new issue as appropriate. (so a big thank you for working on this with backporting in mind, regardless of your own motivating reasons!) |
Me too (SUSE). I have a hard time to persuade myself that this CVE truly deserves a 5.3 score. |
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
I'm trying to not argue about CVE severity/score. I let the security experts decide that :-) Well, I have opinions about it, but I prefer to keep them for myself 🤣. |
|
On Mon Dec 18, 2023 at 3:17 PM CET, Victor Stinner wrote:
> Me too (SUSE). I have a hard time to persuade myself [that this CVE truly deserves a 5.3 score](https://bugzilla.suse.com/show_bug.cgi?id=1210638).
I'm trying to not argue about CVE severity/score. I let the security experts decide that :-) Well, I have opinions about it, but I prefer to keep them for myself 🤣.
Exactly.
|
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel>
…n email.parseaddr() (python#111116) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer. Co-Authored-By: Thomas Dwyer <github@tomd.tel> Changes for Python 2: - Define encoding for test_email - Adjust import so we don't need change the tests - Do not use f-strings - Do not use SubTest - KW only function arguments are not supported
Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). Add an optional 'strict' parameter to getaddresses() and parseaddr() functions. Patch by Thomas Dwyer.
📚 Documentation preview 📚: https://cpython-previews--111116.org.readthedocs.build/