diff options
author | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-05-06 08:45:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-06 08:45:23 +0200 |
commit | e1e81aa1c4427411e3c68facdd761229ffea6f6f (patch) | |
tree | 6afff14e0eba2452db3add415e60fe0219aec75e /django/core/validators.py | |
parent | a708f39ce67af174df90c5b5e50ad1976cec7cb8 (diff) | |
download | django-e1e81aa1c4427411e3c68facdd761229ffea6f6f.tar.gz |
Fixed #32713, Fixed CVE-2021-32052 -- Prevented newlines and tabs from being accepted in URLValidator on Python 3.9.5+.
In Python 3.9.5+ urllib.parse() automatically removes ASCII newlines
and tabs from URLs [1, 2]. Unfortunately it created an issue in
the URLValidator. URLValidator uses urllib.urlsplit() and
urllib.urlunsplit() for creating a URL variant with Punycode which no
longer contains newlines and tabs in Python 3.9.5+. As a consequence,
the regular expression matched the URL (without unsafe characters) and
the source value (with unsafe characters) was considered valid.
[1] https://bugs.python.org/issue43882 and
[2] https://github.com/python/cpython/commit/76cd81d60310d65d01f9d7b48a8985d8ab89c8b4
Diffstat (limited to 'django/core/validators.py')
-rw-r--r-- | django/core/validators.py | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/django/core/validators.py b/django/core/validators.py index a385819510..f9abec602c 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -92,6 +92,7 @@ class URLValidator(RegexValidator): r'\Z', re.IGNORECASE) message = _('Enter a valid URL.') schemes = ['http', 'https', 'ftp', 'ftps'] + unsafe_chars = frozenset('\t\r\n') def __init__(self, schemes=None, **kwargs): super().__init__(**kwargs) @@ -101,6 +102,8 @@ class URLValidator(RegexValidator): def __call__(self, value): if not isinstance(value, str): raise ValidationError(self.message, code=self.code, params={'value': value}) + if self.unsafe_chars.intersection(value): + raise ValidationError(self.message, code=self.code, params={'value': value}) # Check if the scheme is valid. scheme = value.split('://')[0].lower() if scheme not in self.schemes: |