diff --git a/django/forms/fields.py b/django/forms/fields.py index b2a2d2883d..c249c0d29a 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -421,7 +421,7 @@ class RegexField(CharField): 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 = { @@ -532,7 +532,7 @@ class ImageField(FileField): 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 diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py index 9d9d7227b9..9d407d9ea7 100644 --- a/tests/regressiontests/forms/fields.py +++ b/tests/regressiontests/forms/fields.py @@ -767,6 +767,13 @@ u'example@valid-----hyphens.com' >>> 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'' @@ -972,6 +979,32 @@ ValidationError: [u'Enter a valid URL.'] 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): ...