#32008 closed Bug (invalid)
sanitize_address() can add newlines in a header that django.core.mail.EmailMessage will refuse.
Reported by: | Pierre-Elliott Bécue | Owned by: | nobody |
---|---|---|---|
Component: | Core (Mail) | Version: | 2.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Hi,
We've come accross a situation with django 2.2 where, while sanitazing a user address to send a mail in his name, the sanitize_address function, which relies on python's email.header.Header will introduce a newline character in the from header, and therefore, the mail won't get send because django's security features include refusing emails with newlines in headers. It seems to me that no recent version of django addresses this issue.
A simple solution would be to have sanitize_address take a maxlinelen parameter passed to Header. A more complex solution would be to see if the newline is followed by spaces or tabulations, in which case it doesn't seem to pose a security risk as it can't lead to an embedded header.
If you need more input I can give som.
Change History (6)
comment:1 by , 4 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Summary: | django.core.mail.message.sanitize_address can add newlines in a header that django.core.mail.EmailMessage will refuse → sanitize_address() can add newlines in a header that django.core.mail.EmailMessage will refuse. |
comment:2 by , 4 years ago
Hi,
In [1]: from django.core.mail.message import sanitize_address In [2]: from django.core.mail import EmailMessage In [3]: msg = EmailMessage(from_email=sanitize_address("Pierre-Elliott Charles Maxime Antoine Bécue via nm.debian.org <peb@debian.org>", 'utf-8'), subject="Test", body="", to ...: =[sanitize_address("Pierre-Elliott Charles Maxime Antoine Bécue via nm.debian.org <peb@debian.org>", 'utf-8'),]) In [4]: msg.send() --------------------------------------------------------------------------- BadHeaderError Traceback (most recent call last) <ipython-input-13-e80ddd8be11c> in <module>() ----> 1 msg.send() /usr/lib/python3/dist-packages/django/core/mail/message.py in send(self, fail_silently) 304 # send to. 305 return 0 --> 306 return self.get_connection(fail_silently).send_messages([self]) 307 308 def attach(self, filename=None, content=None, mimetype=None): /usr/lib/python3/dist-packages/django/core/mail/backends/smtp.py in send_messages(self, email_messages) 108 num_sent = 0 109 for message in email_messages: --> 110 sent = self._send(message) 111 if sent: 112 num_sent += 1 /usr/lib/python3/dist-packages/django/core/mail/backends/smtp.py in _send(self, email_message) 122 from_email = sanitize_address(email_message.from_email, encoding) 123 recipients = [sanitize_address(addr, encoding) for addr in email_message.recipients()] --> 124 message = email_message.message() 125 try: 126 self.connection.sendmail(from_email, recipients, message.as_bytes(linesep='\r\n')) /usr/lib/python3/dist-packages/django/core/mail/message.py in message(self) 269 msg = self._create_message(msg) 270 msg['Subject'] = self.subject --> 271 msg['From'] = self.extra_headers.get('From', self.from_email) 272 self._set_list_header_if_not_empty(msg, 'To', self.to) 273 self._set_list_header_if_not_empty(msg, 'Cc', self.cc) /usr/lib/python3/dist-packages/django/core/mail/message.py in __setitem__(self, name, val) 182 183 def __setitem__(self, name, val): --> 184 name, val = forbid_multi_line_headers(name, val, self.encoding) 185 MIMEText.__setitem__(self, name, val) 186 /usr/lib/python3/dist-packages/django/core/mail/message.py in forbid_multi_line_headers(name, val, encoding) 60 val = str(val) # val may be lazy 61 if '\n' in val or '\r' in val: ---> 62 raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name)) 63 try: 64 val.encode('ascii') BadHeaderError: Header values can't contain newlines (got '=?utf-8?q?Pierre-Elliott_Charles_Maxime_Antoine_B=C3=A9cue_via_nm=2Edebian?=\n =?utf-8?q?=2Eorg?= <peb@debian.org>' for header 'From')
comment:3 by , 4 years ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
I don't now if the closing was voluntary and why the bug got closed, but as you asked me more info I guess I should reopen it...
comment:4 by , 4 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
forbid_multi_line_headers()
calls sanitize_address()
so you don't need to do this explicitly. Moreover sanitize_address()
is a part of internal and undocumented API, it's not intended for preparing values for EmailMessage()
.
comment:5 by , 4 years ago
Thanks, what's the appropriate entry point to sanitize headers before passing them to EmailMessage then ?
comment:6 by , 4 years ago
I think EmailMessage
is doing sanitizing itself, did you get errors when using your "raw" From address?
Can you provide more details e.g. use case or a sample project?
sanitize_address()
is a part of internal and undocumented API which works fine in Django itself.