From 2342693b31f740a422abf7267c53b4e7bc487c1b Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Mon, 9 Mar 2015 20:05:13 -0400 Subject: [1.4.x] Made is_safe_url() reject URLs that start with control characters. This is a security fix; disclosure to follow shortly. --- django/utils/http.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'django/utils/http.py') diff --git a/django/utils/http.py b/django/utils/http.py index e69a92b578..b8c81a8418 100644 --- a/django/utils/http.py +++ b/django/utils/http.py @@ -4,6 +4,7 @@ import re import sys import urllib import urlparse +import unicodedata from email.utils import formatdate from django.utils.datastructures import MultiValueDict @@ -232,9 +233,10 @@ def is_safe_url(url, host=None): Always returns ``False`` on an empty url. """ + if url is not None: + url = url.strip() 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 @@ -248,5 +250,10 @@ def is_safe_url(url, host=None): # allow this syntax. if not url_info[1] and url_info[0]: return False + # Forbid URLs that start with control characters. Some browsers (like + # Chrome) ignore quite a few control characters at the start of a + # URL and might consider the URL as scheme relative. + if unicodedata.category(unicode(url[0]))[0] == 'C': + return False return (not url_info[1] or url_info[1] == host) and \ (not url_info[0] or url_info[0] in ['http', 'https']) -- cgit v1.3