Anonymous avatar Anonymous committed 7b50c2c

SECURITY ALERT: Corrected regular expressions for URL and email fields.

Certain email addresses/URLs could trigger a catastrophic backtracking
situation, causing 100% CPU and server overload. If deliberately triggered, this
could be the basis of a denial-of-service attack.

This security vulnerability was disclosed in public, so we're skipping our
normal security release process to get the fix out as soon as possible.

This is a security related update. A full announcement will follow.

Comments (0)

Files changed (2)

django/forms/fields.py

 email_re = re.compile(
     r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
     r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
-    r')@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$', re.IGNORECASE)  # domain
+    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain
 
 class EmailField(RegexField):
     default_error_messages = {
 
 url_re = re.compile(
     r'^https?://' # http:// or https://
-    r'(?:(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}|' #domain...
+    r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
     r'localhost|' #localhost...
     r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
     r'(?::\d+)?' # optional port

tests/regressiontests/forms/fields.py

 >>> f.clean('example@valid-with-hyphens.com')
 u'example@valid-with-hyphens.com'
 
+# Check for runaway regex security problem. This will take for-freeking-ever
+# if the security fix isn't in place.
+>>> f.clean('viewx3dtextx26qx3d@yahoo.comx26latlngx3d15854521645943074058')
+Traceback (most recent call last):
+    ...
+ValidationError: [u'Enter a valid e-mail address.']
+
 >>> f = EmailField(required=False)
 >>> f.clean('')
 u''
 Traceback (most recent call last):
 ...
 ValidationError: [u'Enter a valid URL.']
+>>> f.clean('.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('com.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://example.com.')
+u'http://example.com./'
+>>> f.clean('example.com.')
+u'http://example.com./'
+
+# hangs "forever" if catastrophic backtracking in ticket:#11198 not fixed
+>>> f.clean('http://%s' % ("X"*200,))
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+
+# a second test, to make sure the problem is really addressed, even on 
+# domains that don't fail the domain label length check in the regex
+>>> f.clean('http://%s' % ("X"*60,))
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+
 >>> f.clean('http://.com')
 Traceback (most recent call last):
 ...
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.