CVE-2015-8213: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: The get_format function in utils/formats.py in Django before 1.7.x before 1.7.11, 1.8.x before 1.8.7, and 1.9.x before 1.9rc2 might allow remote attackers to obtain sensitive application secrets via a settings key in place of a date/time format setting, as demonstrated by SECRET_KEY.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
Published: 2015-12-07T20:59Z
Repository: https://github.com/django/django
Language: Python
Files changed: django/utils/formats.py, docs/releases/1.7.11.txt, docs/releases/1.8.7.txt, tests/i18n/tests.py
Commit date: 2015-11-24 11:20:29 -0500
Commit message: Fixed a settings leak possibility in the date template filter.

This is a security fix.

Diff: diff --git a/django/utils/formats.py b/django/utils/formats.py
index d2bdda458e..8334682e68 100644
--- a/django/utils/formats.py
+++ b/django/utils/formats.py
@@ -28,10 +28,28 @@ ISO_INPUT_FORMATS = {
         '%Y-%m-%d'
     ],
 }
 
 
+FORMAT_SETTINGS = frozenset([
+    'DECIMAL_SEPARATOR',
+    'THOUSAND_SEPARATOR',
+    'NUMBER_GROUPING',
+    'FIRST_DAY_OF_WEEK',
+    'MONTH_DAY_FORMAT',
+    'TIME_FORMAT',
+    'DATE_FORMAT',
+    'DATETIME_FORMAT',
+    'SHORT_DATE_FORMAT',
+    'SHORT_DATETIME_FORMAT',
+    'YEAR_MONTH_FORMAT',
+    'DATE_INPUT_FORMATS',
+    'TIME_INPUT_FORMATS',
+    'DATETIME_INPUT_FORMATS',
+])
+
+
 def reset_format_cache():
     """Clear any cached formats.
 
     This method is provided primarily for testing purposes,
     so that the effects of cached formats can be removed.
@@ -90,10 +108,12 @@ def get_format(format_type, lang=None, use_l10n=None):
 
     If use_l10n is provided and is not None, that will force the value to
     be localized (or not), overriding the value of settings.USE_L10N.
     """
     format_type = force_str(format_type)
+    if format_type not in FORMAT_SETTINGS:
+        return format_type
     if use_l10n or (use_l10n is None and settings.USE_L10N):
         if lang is None:
             lang = get_language()
         cache_key = (format_type, lang)
         try:
diff --git a/docs/releases/1.7.11.txt b/docs/releases/1.7.11.txt
index 7c6153eab1..8f2f5e7541 100644
--- a/docs/releases/1.7.11.txt
+++ b/docs/releases/1.7.11.txt
@@ -2,11 +2,24 @@
 Django 1.7.11 release notes
 ===========================
 
 *Under development*
 
-Django 1.7.11 fixes a data loss bug in 1.7.10.
+Django 1.7.11 fixes a security issue and a data loss bug in 1.7.10.
+
+Fixed settings leak possibility in ``date`` template filter
+===========================================================
+
+If an application allows users to specify an unvalidated format for dates and
+passes this format to the :tfilter:`date` filter, e.g.
+``{{ last_updated|date:user_date_format }}``, then a malicious user could
+obtain any secret in the application's settings by specifying a settings key
+instead of a date format. e.g. ``"SECRET_KEY"`` instead of ``"j/m/Y"``.
+
+To remedy this, the underlying function used by the ``date`` template filter,
+``django.utils.formats.get_format()``, now only allows accessing the date/time
+formatting settings.
 
 Bugfixes
 ========
 
 * Fixed a data loss possibility with :class:`~django.db.models.Prefetch` if
diff --git a/docs/releases/1.8.7.txt b/docs/releases/1.8.7.txt
index 25f7712f10..77d5e9f901 100644
--- a/docs/releases/1.8.7.txt
+++ b/docs/releases/1.8.7.txt
@@ -2,15 +2,28 @@
 Django 1.8.7 release notes
 ==========================
 
 *Under development*
 
-Django 1.8.7 fixes several bugs in 1.8.6.
+Django 1.8.7 fixes a security issue and several bugs in 1.8.6.
 
 Additionally, Django's vendored version of six, :mod:`django.utils.six`, has
 been upgraded to the latest release (1.10.0).
 
+Fixed settings leak possibility in ``date`` template filter
+===========================================================
+
+If an application allows users to specify an unvalidated format for dates and
+passes this format to the :tfilter:`date` filter, e.g.
+``{{ last_updated|date:user_date_format }}``, then a malicious user could
+obtain any secret in the application's settings by specifying a settings key
+instead of a date format. e.g. ``"SECRET_KEY"`` instead of ``"j/m/Y"``.
+
+To remedy this, the underlying function used by the ``date`` template filter,
+``django.utils.formats.get_format()``, now only allows accessing the date/time
+formatting settings.
+
 Bugfixes
 ========
 
 * Fixed a crash of the debug view during the autumn DST change when
   :setting:`USE_TZ` is ``False`` and ``pytz`` is installed.
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 1de7b11b81..fd332c596e 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -1247,10 +1247,13 @@ class FormattingTests(SimpleTestCase):
                 template_as_hidden.render(context),
                 '<input id="id_date_added" name="date_added" type="hidden" value="31.12.2009 06:00:00" />;'
                 '<input id="id_cents_paid" name="cents_paid" type="hidden" value="59,47" />'
             )
 
+    def test_format_arbitrary_settings(self):
+        self.assertEqual(get_format('DEBUG'), 'DEBUG')
+
 
 class MiscTests(SimpleTestCase):
 
     def setUp(self):
         super(MiscTests, self).setUp()

Vulnerable code: Django 1.7.11 fixes a data loss bug in 1.7.10.
Django 1.8.7 fixes several bugs in 1.8.6.
Fixed code: FORMAT_SETTINGS = frozenset([
    'DECIMAL_SEPARATOR',
    'THOUSAND_SEPARATOR',
    'NUMBER_GROUPING',
    'FIRST_DAY_OF_WEEK',
    'MONTH_DAY_FORMAT',
    'TIME_FORMAT',
    'DATE_FORMAT',
    'DATETIME_FORMAT',
    'SHORT_DATE_FORMAT',
    'SHORT_DATETIME_FORMAT',
    'YEAR_MONTH_FORMAT',
    'DATE_INPUT_FORMATS',
    'TIME_INPUT_FORMATS',
    'DATETIME_INPUT_FORMATS',
])


    if format_type not in FORMAT_SETTINGS:
        return format_type
Django 1.7.11 fixes a security issue and a data loss bug in 1.7.10.

Fixed settings leak possibility in ``date`` template filter
===========================================================

If an application allows users to specify an unvalidated format for dates and
passes this format to the :tfilter:`date` filter, e.g.
``{{ last_updated|date:user_date_format }}``, then a malicious user could
obtain any secret in the application's settings by specifying a settings key
instead of a date format. e.g. ``"SECRET_KEY"`` instead of ``"j/m/Y"``.

To remedy this, the underlying function used by the ``date`` template filter,
``django.utils.formats.get_format()``, now only allows accessing the date/time
formatting settings.
Django 1.8.7 fixes a security issue and several bugs in 1.8.6.
Fixed settings leak possibility in ``date`` template filter
===========================================================

If an application allows users to specify an unvalidated format for dates and
passes this format to the :tfilter:`date` filter, e.g.
``{{ last_updated|date:user_date_format }}``, then a malicious user could
obtain any secret in the application's settings by specifying a settings key
instead of a date format. e.g. ``"SECRET_KEY"`` instead of ``"j/m/Y"``.

To remedy this, the underlying function used by the ``date`` template filter,
``django.utils.formats.get_format()``, now only allows accessing the date/time
formatting settings.

    def test_format_arbitrary_settings(self):
        self.assertEqual(get_format('DEBUG'), 'DEBUG')