Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #1135 -- Changed django.core.mail functions not to allow newlin…

…es in headers

git-svn-id: http://code.djangoproject.com/svn/django/trunk@1795 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 8b5c2192e8698f777102cf56bdbed2170df09cc0 1 parent f7f812c
Adrian Holovaty authored
9  django/core/mail.py
@@ -4,6 +4,13 @@
4 4
 from email.MIMEText import MIMEText
5 5
 import smtplib
6 6
 
  7
+class SafeMIMEText(MIMEText):
  8
+    def __setitem__(self, name, val):
  9
+        "Forbids multi-line headers, to prevent header injection."
  10
+        if '\n' in val or '\r' in val:
  11
+            raise ValueError, "Header values can't contain newlines (got %r for header %r)" % (val, name)
  12
+        MIMEText.__setitem__(self, name, val)
  13
+
7 14
 def send_mail(subject, message, from_email, recipient_list, fail_silently=False):
8 15
     """
9 16
     Easy wrapper for sending a single message to a recipient list. All members
@@ -29,7 +36,7 @@ def send_mass_mail(datatuple, fail_silently=False):
29 36
         if not recipient_list:
30 37
             continue
31 38
         from_email = from_email or DEFAULT_FROM_EMAIL
32  
-        msg = MIMEText(message)
  39
+        msg = SafeMIMEText(message)
33 40
         msg['Subject'] = subject
34 41
         msg['From'] = from_email
35 42
         msg['To'] = ', '.join(recipient_list)
38  docs/email.txt
@@ -114,3 +114,41 @@ receiving a separate e-mail::
114 114
         ('Subject', 'Message.', 'from@example.com', ['jane@example.com'],
115 115
     )
116 116
     send_mass_mail(datatuple)
  117
+
  118
+Preventing header injection
  119
+===========================
  120
+
  121
+**New in Django development version.**
  122
+
  123
+`Header injection`_ is a security exploit in which an attacker inserts extra
  124
+e-mail headers to control the "To:" and "From:" in e-mail messages that your
  125
+scripts generate.
  126
+
  127
+The Django e-mail functions outlined above all protect against header injection
  128
+by forbidding newlines in header values. If any ``subject``, ``from_email`` or
  129
+``recipient_list`` contains a newline, the e-mail function (e.g.
  130
+``send_mail()``) will raise ``ValueError`` and, hence, will not send the
  131
+e-mail. It's your responsibility to validate all data before passing it to the
  132
+e-mail functions.
  133
+
  134
+Here's an example view that takes a ``subject``, ``message`` and ``from_email``
  135
+from the request's POST data, sends that to admin@example.com and redirects to
  136
+"/contact/thanks/" when it's done::
  137
+
  138
+    from django.core.mail import send_mail
  139
+
  140
+    def send_email(request):
  141
+        subject = request.POST.get('subject', '')
  142
+        message = request.POST.get('message', '')
  143
+        from_email = request.POST.get('from_email', '')
  144
+        if subject and message and from_email \
  145
+                and '\n' not in subject and '\n' not in message
  146
+                and '\n' not in from_email:
  147
+            send_mail(subject, message, from_email, ['admin@example.com'])
  148
+            return HttpResponseRedirect('/contact/thanks/')
  149
+        else:
  150
+            # In reality we'd use a manipulator
  151
+            # to get proper validation errors.
  152
+            return HttpResponse('Make sure all fields are entered and valid.')
  153
+
  154
+.. _Header injection: http://securephp.damonkohler.com/index.php/Email_Injection

0 notes on commit 8b5c219

Please sign in to comment.
Something went wrong with that request. Please try again.