[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#859517: unblock: python-django/1.10.7-1



Package: release.debian.org
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: python-modules-team@lists.alioth.debian.org

Dear release team,

Please consider unblocking python-django 1.10.7-1 for stretch. The
relevant debian/changelog entry is:

python-django (1:1.10.7-1) unstable; urgency=medium

  * New upstream security release:

    - CVE-2017-7233: Open redirect and possible XSS attack via user-supplied
      numeric redirect URLs.

      Django relies on user input in some cases (e.g.
      django.contrib.auth.views.login() and i18n) to redirect the user to an
      "on success" URL. The security check for these redirects (namely
      django.utils.http.is_safe_url()) considered some numeric URLs (e.g.
      http:999999999) "safe" when they shouldn't be.

      Also, if a developer relies on is_safe_url() to provide safe redirect
      targets and puts such a URL into a link, they could suffer from an XSS
      attack. (Closes: #859515)

    - CVE-2017-7234: Open redirect vulnerability in django.views.static.serve().

      A maliciously crafted URL to a Django site using the
      django.views.static.serve() view could redirect to any other domain. The
      view no longer does any redirects as they don't provide any known,
      useful functionality.

      Note, however, that this view has always carried a warning that it is
      not hardened for production use and should be used only as a development
      aid. Thanks Phithon Gong for reporting this issue. (Closes: #859516)

Debdiff attached.


Regards,

-- 
      ,''`.
     : :'  :     Chris Lamb
     `. `'`      lamby@debian.org / chris-lamb.co.uk
       `-
diff -Nru python-django-1.10.6/AUTHORS python-django-1.10.7/AUTHORS
--- python-django-1.10.6/AUTHORS	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/AUTHORS	2017-04-04 16:16:56.000000000 +0200
@@ -692,6 +692,7 @@
     Stanislaus Madueke
     starrynight <cmorgh@gmail.com>
     Stefane Fermgier <sf@fermigier.com>
+    Stefano Rivera <stefano@rivera.za.net>
     Stéphane Raimbault <stephane.raimbault@gmail.com>
     Stephan Jaekel <steph@rdev.info>
     Stephen Burrows <stephen.r.burrows@gmail.com>
diff -Nru python-django-1.10.6/debian/changelog python-django-1.10.7/debian/changelog
--- python-django-1.10.6/debian/changelog	2017-03-01 21:27:22.000000000 +0100
+++ python-django-1.10.7/debian/changelog	2017-04-04 17:53:30.000000000 +0200
@@ -1,3 +1,33 @@
+python-django (1:1.10.7-1) unstable; urgency=medium
+
+  * New upstream security release:
+
+    - CVE-2017-7233: Open redirect and possible XSS attack via user-supplied
+      numeric redirect URLs.
+
+      Django relies on user input in some cases (e.g.
+      django.contrib.auth.views.login() and i18n) to redirect the user to an
+      "on success" URL. The security check for these redirects (namely
+      django.utils.http.is_safe_url()) considered some numeric URLs (e.g.
+      http:999999999) "safe" when they shouldn't be.
+
+      Also, if a developer relies on is_safe_url() to provide safe redirect
+      targets and puts such a URL into a link, they could suffer from an XSS
+      attack. (Closes: #859515)
+
+    - CVE-2017-7234: Open redirect vulnerability in django.views.static.serve().
+
+      A maliciously crafted URL to a Django site using the
+      django.views.static.serve() view could redirect to any other domain. The
+      view no longer does any redirects as they don't provide any known,
+      useful functionality.
+
+      Note, however, that this view has always carried a warning that it is
+      not hardened for production use and should be used only as a development
+      aid. Thanks Phithon Gong for reporting this issue. (Closes: #859516)
+
+ -- Chris Lamb <lamby@debian.org>  Tue, 04 Apr 2017 17:53:30 +0200
+
 python-django (1:1.10.6-1) unstable; urgency=medium
 
   * New upstream bugfix release:
diff -Nru python-django-1.10.6/debian/.git-dpm python-django-1.10.7/debian/.git-dpm
--- python-django-1.10.6/debian/.git-dpm	2017-03-01 21:27:22.000000000 +0100
+++ python-django-1.10.7/debian/.git-dpm	2017-04-04 17:53:30.000000000 +0200
@@ -1,11 +1,11 @@
 # see git-dpm(1) from git-dpm package
-9e1c5de966ec84bda893f71e4d24080bfb53134e
-9e1c5de966ec84bda893f71e4d24080bfb53134e
-6af4842fcd60f750ff0cca6d0265854bd0910160
-6af4842fcd60f750ff0cca6d0265854bd0910160
-python-django_1.10.6.orig.tar.gz
-fd39b2134bafbd5b4af4500a948158abf3961e2b
-7734864
+0e464e28dd41c3a8d8fc0f3317650ec4e029b8c5
+0e464e28dd41c3a8d8fc0f3317650ec4e029b8c5
+f18dfc589f0b4a909be9e0cdcf48b70b4f3a7e4e
+f18dfc589f0b4a909be9e0cdcf48b70b4f3a7e4e
+python-django_1.10.7.orig.tar.gz
+5edd13a642460c33cdaf8e8166eccf6b2a2555df
+7737654
 debianTag="debian/%e%%%v"
 patchedTag="debian/patches/%e%%%v"
 upstreamTag="upstream/%e%%%u"
diff -Nru python-django-1.10.6/debian/patches/02_disable-sources-in-sphinxdoc.diff python-django-1.10.7/debian/patches/02_disable-sources-in-sphinxdoc.diff
--- python-django-1.10.6/debian/patches/02_disable-sources-in-sphinxdoc.diff	2017-03-01 21:27:22.000000000 +0100
+++ python-django-1.10.7/debian/patches/02_disable-sources-in-sphinxdoc.diff	2017-04-04 17:53:30.000000000 +0200
@@ -1,4 +1,4 @@
-From 6b7a6fd2d8bd46eaee2f9d59269fab42178ea231 Mon Sep 17 00:00:00 2001
+From fbe85f8899cacc79be7864d853e80899288d3e4c Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hertzog@debian.org>
 Date: Sun, 11 Oct 2015 11:43:19 +1100
 Subject: Disable creation of _sources directory by Sphinx
diff -Nru python-django-1.10.6/debian/patches/06_use_debian_geoip_database_as_default.diff python-django-1.10.7/debian/patches/06_use_debian_geoip_database_as_default.diff
--- python-django-1.10.6/debian/patches/06_use_debian_geoip_database_as_default.diff	2017-03-01 21:27:22.000000000 +0100
+++ python-django-1.10.7/debian/patches/06_use_debian_geoip_database_as_default.diff	2017-04-04 17:53:30.000000000 +0200
@@ -1,4 +1,4 @@
-From 9e1c5de966ec84bda893f71e4d24080bfb53134e Mon Sep 17 00:00:00 2001
+From 0e464e28dd41c3a8d8fc0f3317650ec4e029b8c5 Mon Sep 17 00:00:00 2001
 From: Tapio Rantala <tapio.rantala@iki.fi>
 Date: Sun, 11 Oct 2015 11:43:20 +1100
 Subject: Use Debian GeoIP database path as default
diff -Nru python-django-1.10.6/django/contrib/admin/widgets.py python-django-1.10.7/django/contrib/admin/widgets.py
--- python-django-1.10.6/django/contrib/admin/widgets.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/django/contrib/admin/widgets.py	2017-04-04 16:16:56.000000000 +0200
@@ -337,6 +337,9 @@
     def value_from_datadict(self, data, files, name):
         return self.widget.value_from_datadict(data, files, name)
 
+    def value_omitted_from_data(self, data, files, name):
+        return self.widget.value_omitted_from_data(data, files, name)
+
     def id_for_label(self, id_):
         return self.widget.id_for_label(id_)
 
diff -Nru python-django-1.10.6/django/forms/widgets.py python-django-1.10.7/django/forms/widgets.py
--- python-django-1.10.6/django/forms/widgets.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/django/forms/widgets.py	2017-04-04 16:16:56.000000000 +0200
@@ -631,6 +631,11 @@
             return data.getlist(name)
         return data.get(name)
 
+    def value_omitted_from_data(self, data, files, name):
+        # An unselected <select multiple> doesn't appear in POST data, so it's
+        # never known if the value is actually omitted.
+        return False
+
 
 @html_safe
 @python_2_unicode_compatible
diff -Nru python-django-1.10.6/django/__init__.py python-django-1.10.7/django/__init__.py
--- python-django-1.10.6/django/__init__.py	2017-03-01 14:28:27.000000000 +0100
+++ python-django-1.10.7/django/__init__.py	2017-04-04 16:19:26.000000000 +0200
@@ -2,7 +2,7 @@
 
 from django.utils.version import get_version
 
-VERSION = (1, 10, 6, 'final', 0)
+VERSION = (1, 10, 7, 'final', 0)
 
 __version__ = get_version(VERSION)
 
diff -Nru python-django-1.10.6/django/utils/http.py python-django-1.10.7/django/utils/http.py
--- python-django-1.10.6/django/utils/http.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/django/utils/http.py	2017-04-04 16:18:14.000000000 +0200
@@ -16,9 +16,20 @@
 from django.utils.functional import keep_lazy_text
 from django.utils.six.moves.urllib.parse import (
     quote, quote_plus, unquote, unquote_plus, urlencode as original_urlencode,
-    urlparse,
 )
 
+if six.PY2:
+    from urlparse import (
+        ParseResult, SplitResult, _splitnetloc, _splitparams, scheme_chars,
+        uses_params,
+    )
+    _coerce_args = None
+else:
+    from urllib.parse import (
+        ParseResult, SplitResult, _coerce_args, _splitnetloc, _splitparams,
+        scheme_chars, uses_params,
+    )
+
 ETAG_MATCH = re.compile(r'(?:W/)?"((?:\\.|[^"])*)"')
 
 MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
@@ -298,12 +309,64 @@
     return _is_safe_url(url, host) and _is_safe_url(url.replace('\\', '/'), host)
 
 
+# Copied from urllib.parse.urlparse() but uses fixed urlsplit() function.
+def _urlparse(url, scheme='', allow_fragments=True):
+    """Parse a URL into 6 components:
+    <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
+    Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
+    Note that we don't break the components up in smaller bits
+    (e.g. netloc is a single string) and we don't expand % escapes."""
+    if _coerce_args:
+        url, scheme, _coerce_result = _coerce_args(url, scheme)
+    splitresult = _urlsplit(url, scheme, allow_fragments)
+    scheme, netloc, url, query, fragment = splitresult
+    if scheme in uses_params and ';' in url:
+        url, params = _splitparams(url)
+    else:
+        params = ''
+    result = ParseResult(scheme, netloc, url, params, query, fragment)
+    return _coerce_result(result) if _coerce_args else result
+
+
+# Copied from urllib.parse.urlsplit() with
+# https://github.com/python/cpython/pull/661 applied.
+def _urlsplit(url, scheme='', allow_fragments=True):
+    """Parse a URL into 5 components:
+    <scheme>://<netloc>/<path>?<query>#<fragment>
+    Return a 5-tuple: (scheme, netloc, path, query, fragment).
+    Note that we don't break the components up in smaller bits
+    (e.g. netloc is a single string) and we don't expand % escapes."""
+    if _coerce_args:
+        url, scheme, _coerce_result = _coerce_args(url, scheme)
+    allow_fragments = bool(allow_fragments)
+    netloc = query = fragment = ''
+    i = url.find(':')
+    if i > 0:
+        for c in url[:i]:
+            if c not in scheme_chars:
+                break
+        else:
+            scheme, url = url[:i].lower(), url[i + 1:]
+
+    if url[:2] == '//':
+        netloc, url = _splitnetloc(url, 2)
+        if (('[' in netloc and ']' not in netloc) or
+                (']' in netloc and '[' not in netloc)):
+            raise ValueError("Invalid IPv6 URL")
+    if allow_fragments and '#' in url:
+        url, fragment = url.split('#', 1)
+    if '?' in url:
+        url, query = url.split('?', 1)
+    v = SplitResult(scheme, netloc, url, query, fragment)
+    return _coerce_result(v) if _coerce_args else v
+
+
 def _is_safe_url(url, host):
     # Chrome considers any URL with more than two slashes to be absolute, but
     # urlparse is not so flexible. Treat any url with three slashes as unsafe.
     if url.startswith('///'):
         return False
-    url_info = urlparse(url)
+    url_info = _urlparse(url)
     # Forbid URLs like http:///example.com - with a scheme, but without a hostname.
     # In that URL, example.com is not the hostname but, a path component. However,
     # Chrome will still consider example.com to be the hostname, so we must not
diff -Nru python-django-1.10.6/django/views/static.py python-django-1.10.7/django/views/static.py
--- python-django-1.10.6/django/views/static.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/django/views/static.py	2017-04-04 16:18:14.000000000 +0200
@@ -12,9 +12,9 @@
 
 from django.http import (
     FileResponse, Http404, HttpResponse, HttpResponseNotModified,
-    HttpResponseRedirect,
 )
 from django.template import Context, Engine, TemplateDoesNotExist, loader
+from django.utils._os import safe_join
 from django.utils.http import http_date, parse_http_date
 from django.utils.six.moves.urllib.parse import unquote
 from django.utils.translation import ugettext as _, ugettext_lazy
@@ -36,25 +36,11 @@
     but if you'd like to override it, you can create a template called
     ``static/directory_index.html``.
     """
-    path = posixpath.normpath(unquote(path))
-    path = path.lstrip('/')
-    newpath = ''
-    for part in path.split('/'):
-        if not part:
-            # Strip empty path components.
-            continue
-        drive, part = os.path.splitdrive(part)
-        head, part = os.path.split(part)
-        if part in (os.curdir, os.pardir):
-            # Strip '.' and '..' in path.
-            continue
-        newpath = os.path.join(newpath, part).replace('\\', '/')
-    if newpath and path != newpath:
-        return HttpResponseRedirect(newpath)
-    fullpath = os.path.join(document_root, newpath)
+    path = posixpath.normpath(unquote(path)).lstrip('/')
+    fullpath = safe_join(document_root, path)
     if os.path.isdir(fullpath):
         if show_indexes:
-            return directory_index(newpath, fullpath)
+            return directory_index(path, fullpath)
         raise Http404(_("Directory indexes are not allowed here."))
     if not os.path.exists(fullpath):
         raise Http404(_('"%(path)s" does not exist') % {'path': fullpath})
diff -Nru python-django-1.10.6/Django.egg-info/PKG-INFO python-django-1.10.7/Django.egg-info/PKG-INFO
--- python-django-1.10.6/Django.egg-info/PKG-INFO	2017-03-01 14:30:41.000000000 +0100
+++ python-django-1.10.7/Django.egg-info/PKG-INFO	2017-04-04 16:20:27.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.10.6
+Version: 1.10.7
 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
 Home-page: http://www.djangoproject.com/
 Author: Django Software Foundation
diff -Nru python-django-1.10.6/Django.egg-info/SOURCES.txt python-django-1.10.7/Django.egg-info/SOURCES.txt
--- python-django-1.10.6/Django.egg-info/SOURCES.txt	2017-03-01 14:30:41.000000000 +0100
+++ python-django-1.10.7/Django.egg-info/SOURCES.txt	2017-04-04 16:20:27.000000000 +0200
@@ -3448,6 +3448,7 @@
 docs/releases/1.10.4.txt
 docs/releases/1.10.5.txt
 docs/releases/1.10.6.txt
+docs/releases/1.10.7.txt
 docs/releases/1.10.txt
 docs/releases/1.2.1.txt
 docs/releases/1.2.2.txt
@@ -3534,6 +3535,7 @@
 docs/releases/1.8.15.txt
 docs/releases/1.8.16.txt
 docs/releases/1.8.17.txt
+docs/releases/1.8.18.txt
 docs/releases/1.8.2.txt
 docs/releases/1.8.3.txt
 docs/releases/1.8.4.txt
diff -Nru python-django-1.10.6/docs/howto/custom-template-tags.txt python-django-1.10.7/docs/howto/custom-template-tags.txt
--- python-django-1.10.6/docs/howto/custom-template-tags.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/howto/custom-template-tags.txt	2017-04-04 16:16:53.000000000 +0200
@@ -499,7 +499,7 @@
 
 .. code-block:: html+django
 
-    {% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
+    {% current_time "%Y-%m-%d %I:%M %p" as the_time %}
     <p>The time is {{ the_time }}.</p>
 
 .. _howto-custom-template-tags-inclusion-tags:
diff -Nru python-django-1.10.6/docs/ref/contrib/gis/functions.txt python-django-1.10.7/docs/ref/contrib/gis/functions.txt
--- python-django-1.10.6/docs/ref/contrib/gis/functions.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/ref/contrib/gis/functions.txt	2017-04-04 16:16:56.000000000 +0200
@@ -373,9 +373,7 @@
 *Availability*: PostGIS, Oracle, SpatiaLite (â?¥ 4.0)
 
 Accepts a single geographic field or expression and returns the perimeter of the
-geometry field as a :class:`~django.contrib.gis.measure.Distance` object. On
-MySQL, a raw float value is returned, as it's not possible to automatically
-determine the unit of the field.
+geometry field as a :class:`~django.contrib.gis.measure.Distance` object.
 
 ``PointOnSurface``
 ==================
diff -Nru python-django-1.10.6/docs/ref/databases.txt python-django-1.10.7/docs/ref/databases.txt
--- python-django-1.10.6/docs/ref/databases.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/ref/databases.txt	2017-04-04 16:16:56.000000000 +0200
@@ -720,9 +720,9 @@
 Oracle notes
 ============
 
-Django supports `Oracle Database Server`_ versions 11.2 and higher. Version
-4.3.1 or higher of the `cx_Oracle`_ Python driver is required, although we
-recommend version 5.1.3 or later as these versions support Python 3.
+Django supports `Oracle Database Server`_ versions 11.2 and higher. Versions
+4.3.1 through 5.2.1 of the `cx_Oracle`_ Python driver are supported, although
+5.1.3 or later is recommended as these versions support Python 3.
 
 Note that due to a Unicode-corruption bug in ``cx_Oracle`` 5.0, that
 version of the driver should **not** be used with Django;
diff -Nru python-django-1.10.6/docs/ref/django-admin.txt python-django-1.10.7/docs/ref/django-admin.txt
--- python-django-1.10.6/docs/ref/django-admin.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/ref/django-admin.txt	2017-04-04 16:16:56.000000000 +0200
@@ -1615,7 +1615,7 @@
 
     django-admin migrate --traceback
 
-.. django-admin-option:: --verbosity {0,1,2,3}, --v {0,1,2,3}
+.. django-admin-option:: --verbosity {0,1,2,3}, -v {0,1,2,3}
 
 Specifies the amount of notification and debug information that a command
 should print to the console.
diff -Nru python-django-1.10.6/docs/ref/forms/widgets.txt python-django-1.10.7/docs/ref/forms/widgets.txt
--- python-django-1.10.6/docs/ref/forms/widgets.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/ref/forms/widgets.txt	2017-04-04 16:16:56.000000000 +0200
@@ -281,11 +281,12 @@
         The method's result affects whether or not a field in a model form
         :ref:`falls back to its default <topics-modelform-save>`.
 
-        Special cases are :class:`~django.forms.CheckboxInput` and
-        :class:`~django.forms.CheckboxSelectMultiple`, which always return
-        ``False`` because an unchecked checkbox doesn't appear in the data of
-        an HTML form submission, so it's unknown whether or not the user
-        actually submitted a value.
+        Special cases are :class:`~django.forms.CheckboxInput`,
+        :class:`~django.forms.CheckboxSelectMultiple`, and
+        :class:`~django.forms.SelectMultiple`, which always return
+        ``False`` because an unchecked checkbox and unselected
+        ``<select multiple>`` don't appear in the data of an HTML form
+        submission, so it's unknown whether or not the user submitted a value.
 
     .. method:: use_required_attribute(initial)
 
diff -Nru python-django-1.10.6/docs/ref/models/expressions.txt python-django-1.10.7/docs/ref/models/expressions.txt
--- python-django-1.10.6/docs/ref/models/expressions.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/ref/models/expressions.txt	2017-04-04 16:16:56.000000000 +0200
@@ -26,8 +26,8 @@
 
 .. code-block:: python
 
-    from django.db.models import F, Count
-    from django.db.models.functions import Length, Upper, Value
+    from django.db.models import F, Count, Value
+    from django.db.models.functions import Length, Upper
 
     # Find companies that have more employees than chairs.
     Company.objects.filter(num_employees__gt=F('num_chairs'))
diff -Nru python-django-1.10.6/docs/ref/templates/builtins.txt python-django-1.10.7/docs/ref/templates/builtins.txt
--- python-django-1.10.6/docs/ref/templates/builtins.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/ref/templates/builtins.txt	2017-04-04 16:16:56.000000000 +0200
@@ -1396,12 +1396,18 @@
 the output would be the string ``"09/01/2008"`` (the ``"SHORT_DATE_FORMAT"``
 format specifier for the ``es`` locale as shipped with Django is ``"d/m/Y"``).
 
-When used without a format string::
+When used without a format string, the ``DATE_FORMAT`` format specifier is
+used. Assuming the same settings as the previous example::
 
     {{ value|date }}
 
-...the formatting string defined in the :setting:`DATE_FORMAT` setting will be
-used, without applying any localization.
+outputs ``9 de Enero de 2008`` (the ``DATE_FORMAT`` format specifier for the
+``es`` locale is ``r'j \d\e F \d\e Y'``.
+
+.. versionchanged:: 1.10
+
+    In older versions, the :setting:`DATE_FORMAT` setting (without
+    localization) is always used when a format string isn't given.
 
 You can combine ``date`` with the :tfilter:`time` filter to render a full
 representation of a ``datetime`` value. E.g.::
@@ -2122,12 +2128,19 @@
 accept the timezone-related :ref:`format specifiers
 <date-and-time-formatting-specifiers>` ``'e'``, ``'O'`` , ``'T'`` and ``'Z'``.
 
-When used without a format string::
+When used without a format string, the ``TIME_FORMAT`` format specifier is
+used::
 
     {{ value|time }}
 
-...the formatting string defined in the :setting:`TIME_FORMAT` setting will be
-used, without applying any localization.
+is the same as::
+
+    {{ value|time:"TIME_FORMAT" }}
+
+.. versionchanged:: 1.10
+
+    In older versions, the :setting:`TIME_FORMAT` setting (without
+    localization) is always used when a format string isn't given.
 
 .. templatefilter:: timesince
 
diff -Nru python-django-1.10.6/docs/releases/1.10.6.txt python-django-1.10.7/docs/releases/1.10.6.txt
--- python-django-1.10.6/docs/releases/1.10.6.txt	2017-03-01 14:28:17.000000000 +0100
+++ python-django-1.10.7/docs/releases/1.10.6.txt	2017-04-04 16:16:53.000000000 +0200
@@ -19,7 +19,7 @@
   or ``IntegerField`` from ``DateField`` (:ticket:`27828`).
 
 * Fixed query expression date subtraction accuracy on PostgreSQL for
-  differences large an a month (:ticket:`27856`).
+  differences larger than a month (:ticket:`27856`).
 
 * Fixed a ``GDALException`` raised by ``GDALClose`` on GDAL â?¥ 2.0
   (:ticket:`27479`).
diff -Nru python-django-1.10.6/docs/releases/1.10.7.txt python-django-1.10.7/docs/releases/1.10.7.txt
--- python-django-1.10.6/docs/releases/1.10.7.txt	1970-01-01 01:00:00.000000000 +0100
+++ python-django-1.10.7/docs/releases/1.10.7.txt	2017-04-04 16:18:14.000000000 +0200
@@ -0,0 +1,39 @@
+===========================
+Django 1.10.7 release notes
+===========================
+
+*April 4, 2017*
+
+Django 1.10.7 fixes two security issues and a bug in 1.10.6.
+
+CVE-2017-7233: Open redirect and possible XSS attack via user-supplied numeric 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 check for these
+redirects (namely ``django.utils.http.is_safe_url()``) considered some numeric
+URLs (e.g. ``http:999999999``) "safe" when they shouldn't be.
+
+Also, if a developer relies on ``is_safe_url()`` to provide safe redirect
+targets and puts such a URL into a link, they could suffer from an XSS attack.
+
+CVE-2017-7234: Open redirect vulnerability in ``django.views.static.serve()``
+=============================================================================
+
+A maliciously crafted URL to a Django site using the
+:func:`~django.views.static.serve` view could redirect to any other domain. The
+view no longer does any redirects as they don't provide any known, useful
+functionality.
+
+Note, however, that this view has always carried a warning that it is not
+hardened for production use and should be used only as a development aid.
+
+Bugfixes
+========
+
+* Made admin's ``RelatedFieldWidgetWrapper`` use the wrapped widget's
+  ``value_omitted_from_data()`` method (:ticket:`27905`).
+
+* Fixed model form ``default`` fallback for ``SelectMultiple``
+  (:ticket:`27993`).
diff -Nru python-django-1.10.6/docs/releases/1.10.txt python-django-1.10.7/docs/releases/1.10.txt
--- python-django-1.10.6/docs/releases/1.10.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/releases/1.10.txt	2017-04-04 16:16:56.000000000 +0200
@@ -918,6 +918,11 @@
   To adapt, move the fragment outside the template tag:
   ``{% static 'img.svg' %}#fragment``.
 
+* When :setting:`USE_L10N` is ``True``, localization is now applied for the
+  :tfilter:`date` and :tfilter:`time` filters when no format string is
+  specified. The ``DATE_FORMAT`` and ``TIME_FORMAT`` specifiers from the active
+  locale are used instead of the settings of the same name.
+
 .. _deprecated-features-1.10:
 
 Features deprecated in 1.10
diff -Nru python-django-1.10.6/docs/releases/1.8.18.txt python-django-1.10.7/docs/releases/1.8.18.txt
--- python-django-1.10.6/docs/releases/1.8.18.txt	1970-01-01 01:00:00.000000000 +0100
+++ python-django-1.10.7/docs/releases/1.8.18.txt	2017-04-04 16:18:14.000000000 +0200
@@ -0,0 +1,30 @@
+===========================
+Django 1.8.18 release notes
+===========================
+
+*April 4, 2017*
+
+Django 1.8.18 fixes two security issues in 1.8.17.
+
+CVE-2017-7233: Open redirect and possible XSS attack via user-supplied numeric 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 check for these
+redirects (namely ``django.utils.http.is_safe_url()``) considered some numeric
+URLs (e.g. ``http:999999999``) "safe" when they shouldn't be.
+
+Also, if a developer relies on ``is_safe_url()`` to provide safe redirect
+targets and puts such a URL into a link, they could suffer from an XSS attack.
+
+CVE-2017-7234: Open redirect vulnerability in ``django.views.static.serve()``
+=============================================================================
+
+A maliciously crafted URL to a Django site using the
+:func:`~django.views.static.serve` view could redirect to any other domain. The
+view no longer does any redirects as they don't provide any known, useful
+functionality.
+
+Note, however, that this view has always carried a warning that it is not
+hardened for production use and should be used only as a development aid.
diff -Nru python-django-1.10.6/docs/releases/1.9.13.txt python-django-1.10.7/docs/releases/1.9.13.txt
--- python-django-1.10.6/docs/releases/1.9.13.txt	2017-01-23 17:46:17.000000000 +0100
+++ python-django-1.10.7/docs/releases/1.9.13.txt	2017-04-04 16:18:14.000000000 +0200
@@ -2,9 +2,33 @@
 Django 1.9.13 release notes
 ===========================
 
-*Under development*
+*April 4, 2017*
 
-Django 1.9.13 fixes a bug in 1.9.12.
+Django 1.9.13 fixes two security issues and a bug in 1.9.12. This is the final
+release of the 1.9.x series.
+
+CVE-2017-7233: Open redirect and possible XSS attack via user-supplied numeric 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 check for these
+redirects (namely ``django.utils.http.is_safe_url()``) considered some numeric
+URLs (e.g. ``http:999999999``) "safe" when they shouldn't be.
+
+Also, if a developer relies on ``is_safe_url()`` to provide safe redirect
+targets and puts such a URL into a link, they could suffer from an XSS attack.
+
+CVE-2017-7234: Open redirect vulnerability in ``django.views.static.serve()``
+=============================================================================
+
+A maliciously crafted URL to a Django site using the
+:func:`~django.views.static.serve` view could redirect to any other domain. The
+view no longer does any redirects as they don't provide any known, useful
+functionality.
+
+Note, however, that this view has always carried a warning that it is not
+hardened for production use and should be used only as a development aid.
 
 Bugfixes
 ========
diff -Nru python-django-1.10.6/docs/releases/index.txt python-django-1.10.7/docs/releases/index.txt
--- python-django-1.10.6/docs/releases/index.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/releases/index.txt	2017-04-04 16:18:14.000000000 +0200
@@ -25,6 +25,7 @@
 .. toctree::
    :maxdepth: 1
 
+   1.10.7
    1.10.6
    1.10.5
    1.10.4
@@ -58,6 +59,7 @@
 .. toctree::
    :maxdepth: 1
 
+   1.8.18
    1.8.17
    1.8.16
    1.8.15
diff -Nru python-django-1.10.6/docs/topics/forms/modelforms.txt python-django-1.10.7/docs/topics/forms/modelforms.txt
--- python-django-1.10.6/docs/topics/forms/modelforms.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/topics/forms/modelforms.txt	2017-04-04 16:16:56.000000000 +0200
@@ -335,12 +335,14 @@
 If an optional field doesn't appear in the form's data, the resulting model
 instance uses the model field :attr:`~django.db.models.Field.default`, if
 there is one, for that field. This behavior doesn't apply to fields that use
-:class:`~django.forms.CheckboxInput` and
-:class:`~django.forms.CheckboxSelectMultiple` (or any custom widget whose
+:class:`~django.forms.CheckboxInput`,
+:class:`~django.forms.CheckboxSelectMultiple`, or
+:class:`~django.forms.SelectMultiple` (or any custom widget whose
 :meth:`~django.forms.Widget.value_omitted_from_data` method always returns
-``False``) since an unchecked checkbox doesn't appear in the data of an HTML
-form submission. Use a custom form field or widget if you're designing an API
-and want the default fallback for a :class:`~django.db.models.BooleanField`.
+``False``) since an unchecked checkbox and unselected ``<select multiple>``
+don't appear in the data of an HTML form submission. Use a custom form field or
+widget if you're designing an API and want the default fallback behavior for a
+field that uses one of these widgets.
 
 .. versionchanged:: 1.10.1
 
diff -Nru python-django-1.10.6/docs/topics/migrations.txt python-django-1.10.7/docs/topics/migrations.txt
--- python-django-1.10.6/docs/topics/migrations.txt	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/docs/topics/migrations.txt	2017-04-04 16:16:56.000000000 +0200
@@ -468,7 +468,6 @@
     from django.db import migrations, models
 
     class Migration(migrations.Migration):
-        initial = True
 
         dependencies = [
             ('yourappname', '0001_initial'),
@@ -506,7 +505,6 @@
             person.save()
 
     class Migration(migrations.Migration):
-        initial = True
 
         dependencies = [
             ('yourappname', '0001_initial'),
diff -Nru python-django-1.10.6/PKG-INFO python-django-1.10.7/PKG-INFO
--- python-django-1.10.6/PKG-INFO	2017-03-01 14:30:44.000000000 +0100
+++ python-django-1.10.7/PKG-INFO	2017-04-04 16:20:29.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Django
-Version: 1.10.6
+Version: 1.10.7
 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
 Home-page: http://www.djangoproject.com/
 Author: Django Software Foundation
diff -Nru python-django-1.10.6/tests/admin_widgets/tests.py python-django-1.10.7/tests/admin_widgets/tests.py
--- python-django-1.10.6/tests/admin_widgets/tests.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/tests/admin_widgets/tests.py	2017-04-04 16:16:56.000000000 +0200
@@ -631,6 +631,15 @@
         self.assertTrue(wrapper.can_change_related)
         self.assertFalse(wrapper.can_delete_related)
 
+    def test_widget_delegates_value_omitted_from_data(self):
+        class CustomWidget(forms.Select):
+            def value_omitted_from_data(self, data, files, name):
+                return False
+        rel = models.Album._meta.get_field('band').remote_field
+        widget = CustomWidget()
+        wrapper = widgets.RelatedFieldWidgetWrapper(widget, rel, widget_admin_site)
+        self.assertIs(wrapper.value_omitted_from_data({}, {}, 'band'), False)
+
 
 @override_settings(ROOT_URLCONF='admin_widgets.urls')
 class AdminWidgetSeleniumTestCase(AdminSeleniumTestCase):
diff -Nru python-django-1.10.6/tests/backends/tests.py python-django-1.10.7/tests/backends/tests.py
--- python-django-1.10.6/tests/backends/tests.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/tests/backends/tests.py	2017-04-04 16:16:53.000000000 +0200
@@ -292,6 +292,7 @@
         """
         Regression test for #18130 and #24318.
         """
+        import psycopg2
         from psycopg2.extensions import (
             ISOLATION_LEVEL_READ_COMMITTED as read_committed,
             ISOLATION_LEVEL_SERIALIZABLE as serializable,
@@ -302,7 +303,8 @@
         # PostgreSQL is configured with the default isolation level.
 
         # Check the level on the psycopg2 connection, not the Django wrapper.
-        self.assertEqual(connection.connection.isolation_level, read_committed)
+        default_level = read_committed if psycopg2.__version__ < '2.7' else None
+        self.assertEqual(connection.connection.isolation_level, default_level)
 
         new_connection = connection.copy()
         new_connection.settings_dict['OPTIONS']['isolation_level'] = serializable
diff -Nru python-django-1.10.6/tests/forms_tests/widget_tests/test_selectmultiple.py python-django-1.10.7/tests/forms_tests/widget_tests/test_selectmultiple.py
--- python-django-1.10.6/tests/forms_tests/widget_tests/test_selectmultiple.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/tests/forms_tests/widget_tests/test_selectmultiple.py	2017-04-04 16:16:56.000000000 +0200
@@ -123,3 +123,8 @@
             </optgroup>
             </select>"""
         ))
+
+    def test_value_omitted_from_data(self):
+        widget = self.widget(choices=self.beatles)
+        self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), False)
+        self.assertIs(widget.value_omitted_from_data({'field': 'value'}, {}, 'field'), False)
diff -Nru python-django-1.10.6/tests/model_forms/tests.py python-django-1.10.7/tests/model_forms/tests.py
--- python-django-1.10.6/tests/model_forms/tests.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/tests/model_forms/tests.py	2017-04-04 16:16:56.000000000 +0200
@@ -601,6 +601,22 @@
         self.assertEqual(m1.mode, '')
         self.assertEqual(m1._meta.get_field('mode').get_default(), 'di')
 
+    def test_default_not_populated_on_selectmultiple(self):
+        class PubForm(forms.ModelForm):
+            mode = forms.CharField(required=False, widget=forms.SelectMultiple)
+
+            class Meta:
+                model = PublicationDefaults
+                fields = ('mode',)
+
+        # Empty data doesn't use the model default because an unselected
+        # SelectMultiple doesn't have a value in HTML form submission.
+        mf1 = PubForm({})
+        self.assertEqual(mf1.errors, {})
+        m1 = mf1.save(commit=False)
+        self.assertEqual(m1.mode, '')
+        self.assertEqual(m1._meta.get_field('mode').get_default(), 'di')
+
     def test_prefixed_form_with_default_field(self):
         class PubForm(forms.ModelForm):
             prefix = 'form-prefix'
@@ -1867,7 +1883,7 @@
         )
         article.categories.add(self.c2, self.c3)
         form = ArticleCategoriesForm(instance=article)
-        self.assertEqual(form['categories'].value(), [self.c2.slug, self.c3.slug])
+        six.assertCountEqual(self, form['categories'].value(), [self.c2.slug, self.c3.slug])
 
 
 class ModelOneToOneFieldTests(TestCase):
diff -Nru python-django-1.10.6/tests/requirements/oracle.txt python-django-1.10.7/tests/requirements/oracle.txt
--- python-django-1.10.6/tests/requirements/oracle.txt	2017-01-23 17:46:17.000000000 +0100
+++ python-django-1.10.7/tests/requirements/oracle.txt	2017-04-04 16:16:56.000000000 +0200
@@ -1 +1 @@
-cx_oracle
+cx_oracle < 5.3
diff -Nru python-django-1.10.6/tests/utils_tests/test_http.py python-django-1.10.7/tests/utils_tests/test_http.py
--- python-django-1.10.6/tests/utils_tests/test_http.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/tests/utils_tests/test_http.py	2017-04-04 16:18:14.000000000 +0200
@@ -104,6 +104,8 @@
             r'http://testserver\me:pass@example.com',
             r'http://testserver\@example.com',
             r'http:\\testserver\confirm\me@example.com',
+            'http:999999999',
+            'ftp:9999999999',
             '\n',
         )
         for bad_url in bad_urls:
@@ -119,6 +121,7 @@
             '//testserver/',
             'http://testserver/confirm?email=me@example.com',
             '/url%20with%20spaces/',
+            'path/http:2222222222',
         )
         for good_url in good_urls:
             self.assertTrue(http.is_safe_url(good_url, host='testserver'), "%s should be allowed" % good_url)
diff -Nru python-django-1.10.6/tests/view_tests/tests/test_static.py python-django-1.10.7/tests/view_tests/tests/test_static.py
--- python-django-1.10.6/tests/view_tests/tests/test_static.py	2017-03-01 14:28:15.000000000 +0100
+++ python-django-1.10.7/tests/view_tests/tests/test_static.py	2017-04-04 16:18:14.000000000 +0200
@@ -110,7 +110,7 @@
 
     def test_index(self):
         response = self.client.get('/%s/' % self.prefix)
-        self.assertContains(response, 'Index of /')
+        self.assertContains(response, 'Index of ./')
 
 
 class StaticHelperTest(StaticTests):

Reply to: