Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#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: mail
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 Mariusz Felisiak, 4 years ago

Resolution: needsinfo
Status: newclosed
Summary: django.core.mail.message.sanitize_address can add newlines in a header that django.core.mail.EmailMessage will refusesanitize_address() can add newlines in a header that django.core.mail.EmailMessage will refuse.

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.

comment:2 by Pierre-Elliott Bécue, 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 Pierre-Elliott Bécue, 4 years ago

Resolution: needsinfo
Status: closednew

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 Mariusz Felisiak, 4 years ago

Resolution: invalid
Status: newclosed

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 Pierre-Elliott Bécue, 4 years ago

Thanks, what's the appropriate entry point to sanitize headers before passing them to EmailMessage then ?

comment:6 by Claude Paroz, 4 years ago

I think EmailMessage is doing sanitizing itself, did you get errors when using your "raw" From address?

Note: See TracTickets for help on using tickets.
Back to Top