Moderate severityNVD Advisory· Published Jan 16, 2015· Updated May 6, 2026
CVE-2015-0220
CVE-2015-0220
Description
The django.util.http.is_safe_url function in Django before 1.4.18, 1.6.x before 1.6.10, and 1.7.x before 1.7.3 does not properly handle leading whitespaces, which allows remote attackers to conduct cross-site scripting (XSS) attacks via a crafted URL, related to redirect URLs, as demonstrated by a "\njavascript:" URL.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
DjangoPyPI | < 1.4.18 | 1.4.18 |
DjangoPyPI | >= 1.6, < 1.6.10 | 1.6.10 |
DjangoPyPI | >= 1.7, < 1.7.3 | 1.7.3 |
Affected products
18cpe:2.3:o:canonical:ubuntu_linux:10.04:*:lts:*:*:*:*:*+ 3 more
- cpe:2.3:o:canonical:ubuntu_linux:10.04:*:lts:*:*:*:*:*
- cpe:2.3:o:canonical:ubuntu_linux:12.04:*:lts:*:*:*:*:*
- cpe:2.3:o:canonical:ubuntu_linux:14.04:*:*:*:lts:*:*:*
- cpe:2.3:o:canonical:ubuntu_linux:14.10:*:*:*:*:*:*:*
cpe:2.3:a:djangoproject:django:*:*:*:*:*:*:*:*+ 13 more
- cpe:2.3:a:djangoproject:django:*:*:*:*:*:*:*:*range: <=1.4.17
- cpe:2.3:a:djangoproject:django:1.6:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.1:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.2:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.3:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.4:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.5:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.6:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.7:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.8:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.6.9:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.7:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.7.1:*:*:*:*:*:*:*
- cpe:2.3:a:djangoproject:django:1.7.2:*:*:*:*:*:*:*
Patches
34c241f1b710d[1.4.x] Fixed is_safe_url() to handle leading whitespace.
3 files changed · +19 −3
django/utils/http.py+1 −0 modified@@ -234,6 +234,7 @@ def is_safe_url(url, host=None): """ if not url: return False + url = url.strip() # Chrome treats \ completely as / url = url.replace('\\', '/') # Chrome considers any URL with more than two slashes to be absolute, but
docs/releases/1.4.18.txt+14 −0 modified@@ -31,6 +31,20 @@ development server now does the same. Django's development server is not recommended for production use, but matching the behavior of common production servers reduces the surface area for behavior changes during deployment. +Mitigated possible XSS attack via user-supplied redirect URLs +============================================================= + +Django relies on user input in some cases (e.g. +:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) +to redirect the user to an "on success" URL. The security checks for these +redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading +whitespace on the tested URL and as such considered URLs like +``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to +provide safe redirect targets and put such a URL into a link, they could suffer +from a XSS attack. This bug doesn't affect Django currently, since we only put +this URL into the ``Location`` response header and browsers seem to ignore +JavaScript there. + Bugfixes ========
tests/regressiontests/utils/http.py+4 −3 modified@@ -64,7 +64,7 @@ def test_base36(self): # bad input for n in [-1, sys.maxint+1, '1', 'foo', {1:2}, (1,2,3)]: self.assertRaises(ValueError, http.int_to_base36, n) - + for n in ['#', ' ']: self.assertRaises(ValueError, http.base36_to_int, n) @@ -73,7 +73,7 @@ def test_base36(self): # non-integer input self.assertRaises(TypeError, http.int_to_base36, 3.141) - + # more explicit output testing for n, b36 in [(0, '0'), (1, '1'), (42, '16'), (818469960, 'django')]: self.assertEqual(http.int_to_base36(n), b36) @@ -97,7 +97,8 @@ def test_is_safe_url(self): 'http:/\//example.com', 'http:\/example.com', 'http:/\example.com', - 'javascript:alert("XSS")'): + 'javascript:alert("XSS")' + '\njavascript:alert(x)'): self.assertFalse(http.is_safe_url(bad_url, host='testserver'), "%s should be blocked" % bad_url) for good_url in ('/view/?param=http://example.com', '/view/?param=https://example.com',
72e0b033662f[1.6.x] Fixed is_safe_url() to handle leading whitespace.
4 files changed · +31 −1
django/utils/http.py+1 −0 modified@@ -256,6 +256,7 @@ def is_safe_url(url, host=None): """ if not url: return False + url = url.strip() # Chrome treats \ completely as / url = url.replace('\\', '/') # Chrome considers any URL with more than two slashes to be absolute, but
docs/releases/1.4.18.txt+14 −0 modified@@ -31,6 +31,20 @@ development server now does the same. Django's development server is not recommended for production use, but matching the behavior of common production servers reduces the surface area for behavior changes during deployment. +Mitigated possible XSS attack via user-supplied redirect URLs +============================================================= + +Django relies on user input in some cases (e.g. +:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) +to redirect the user to an "on success" URL. The security checks for these +redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading +whitespace on the tested URL and as such considered URLs like +``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to +provide safe redirect targets and put such a URL into a link, they could suffer +from a XSS attack. This bug doesn't affect Django currently, since we only put +this URL into the ``Location`` response header and browsers seem to ignore +JavaScript there. + Bugfixes ========
docs/releases/1.6.10.txt+14 −0 modified@@ -29,3 +29,17 @@ containing underscores from incoming requests by default. Django's built-in development server now does the same. Django's development server is not recommended for production use, but matching the behavior of common production servers reduces the surface area for behavior changes during deployment. + +Mitigated possible XSS attack via user-supplied redirect URLs +============================================================= + +Django relies on user input in some cases (e.g. +:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) +to redirect the user to an "on success" URL. The security checks for these +redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading +whitespace on the tested URL and as such considered URLs like +``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to +provide safe redirect targets and put such a URL into a link, they could suffer +from a XSS attack. This bug doesn't affect Django currently, since we only put +this URL into the ``Location`` response header and browsers seem to ignore +JavaScript there.
tests/utils_tests/test_http.py+2 −1 modified@@ -109,7 +109,8 @@ def test_is_safe_url(self): 'http:/\//example.com', 'http:\/example.com', 'http:/\example.com', - 'javascript:alert("XSS")'): + 'javascript:alert("XSS")', + '\njavascript:alert(x)'): self.assertFalse(http.is_safe_url(bad_url, host='testserver'), "%s should be blocked" % bad_url) for good_url in ('/view/?param=http://example.com', '/view/?param=https://example.com',
de67dedc771a[1.7.x] Fixed is_safe_url() to handle leading whitespace.
5 files changed · +45 −1
django/utils/http.py+1 −0 modified@@ -272,6 +272,7 @@ def is_safe_url(url, host=None): """ if not url: return False + url = url.strip() # Chrome treats \ completely as / url = url.replace('\\', '/') # Chrome considers any URL with more than two slashes to be absolute, but
docs/releases/1.4.18.txt+14 −0 modified@@ -31,6 +31,20 @@ development server now does the same. Django's development server is not recommended for production use, but matching the behavior of common production servers reduces the surface area for behavior changes during deployment. +Mitigated possible XSS attack via user-supplied redirect URLs +============================================================= + +Django relies on user input in some cases (e.g. +:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) +to redirect the user to an "on success" URL. The security checks for these +redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading +whitespace on the tested URL and as such considered URLs like +``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to +provide safe redirect targets and put such a URL into a link, they could suffer +from a XSS attack. This bug doesn't affect Django currently, since we only put +this URL into the ``Location`` response header and browsers seem to ignore +JavaScript there. + Bugfixes ========
docs/releases/1.6.10.txt+14 −0 modified@@ -29,3 +29,17 @@ containing underscores from incoming requests by default. Django's built-in development server now does the same. Django's development server is not recommended for production use, but matching the behavior of common production servers reduces the surface area for behavior changes during deployment. + +Mitigated possible XSS attack via user-supplied redirect URLs +============================================================= + +Django relies on user input in some cases (e.g. +:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) +to redirect the user to an "on success" URL. The security checks for these +redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading +whitespace on the tested URL and as such considered URLs like +``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to +provide safe redirect targets and put such a URL into a link, they could suffer +from a XSS attack. This bug doesn't affect Django currently, since we only put +this URL into the ``Location`` response header and browsers seem to ignore +JavaScript there.
docs/releases/1.7.3.txt+14 −0 modified@@ -30,6 +30,20 @@ development server now does the same. Django's development server is not recommended for production use, but matching the behavior of common production servers reduces the surface area for behavior changes during deployment. +Mitigated possible XSS attack via user-supplied redirect URLs +============================================================= + +Django relies on user input in some cases (e.g. +:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) +to redirect the user to an "on success" URL. The security checks for these +redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading +whitespace on the tested URL and as such considered URLs like +``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to +provide safe redirect targets and put such a URL into a link, they could suffer +from a XSS attack. This bug doesn't affect Django currently, since we only put +this URL into the ``Location`` response header and browsers seem to ignore +JavaScript there. + Bugfixes ========
tests/utils_tests/test_http.py+2 −1 modified@@ -107,7 +107,8 @@ def test_is_safe_url(self): 'http:/\//example.com', 'http:\/example.com', 'http:/\example.com', - 'javascript:alert("XSS")'): + 'javascript:alert("XSS")', + '\njavascript:alert(x)'): self.assertFalse(http.is_safe_url(bad_url, host='testserver'), "%s should be blocked" % bad_url) for good_url in ('/view/?param=http://example.com', '/view/?param=https://example.com',
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
24- www.djangoproject.com/weblog/2015/jan/13/security/nvdExploitVendor Advisory
- github.com/advisories/GHSA-gv98-g628-m9x5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2015-0220ghsaADVISORY
- lists.fedoraproject.org/pipermail/package-announce/2015-January/148485.htmlnvdWEB
- lists.fedoraproject.org/pipermail/package-announce/2015-January/148608.htmlnvdWEB
- lists.opensuse.org/opensuse-updates/2015-04/msg00001.htmlnvdWEB
- lists.opensuse.org/opensuse-updates/2015-09/msg00035.htmlnvdWEB
- ubuntu.com/usn/usn-2469-1nvdWEB
- github.com/django/django/blob/4555a823fd57e261e1b19c778429473256c8ea08/docs/releases/1.4.18.txtghsaWEB
- github.com/django/django/commit/4c241f1b710da6419d9dca160e80b23b82db7758ghsaWEB
- github.com/django/django/commit/72e0b033662faa11bb7f516f18a132728aa0ae28ghsaWEB
- github.com/django/django/commit/de67dedc771ad2edec15c1d00c083a1a084e1e89ghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/django/PYSEC-2015-5.yamlghsaWEB
- web.archive.org/web/20150128111656/http://secunia.com/advisories/62285ghsaWEB
- web.archive.org/web/20150523054951/http://www.mandriva.com/en/support/security/advisories/advisory/MDVSA-2015:109/ghsaWEB
- web.archive.org/web/20150523054953/http://www.mandriva.com/en/support/security/advisories/advisory/MDVSA-2015:036/ghsaWEB
- web.archive.org/web/20151104201446/http://secunia.com/advisories/62718ghsaWEB
- www.djangoproject.com/weblog/2015/jan/13/securityghsaWEB
- advisories.mageia.org/MGASA-2015-0026.htmlnvd
- secunia.com/advisories/62285nvd
- secunia.com/advisories/62309nvd
- secunia.com/advisories/62718nvd
- www.mandriva.com/security/advisoriesnvd
- www.mandriva.com/security/advisoriesnvd
News mentions
0No linked articles in our index yet.