﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
14808	i18n is not safe.	Stephen Kelly	Tobias Kunze	"This was reported to security@, but was considered a regular bug, not something requiring a security release because it is not a practical attack vector.

If an attacker knows that the string ""Today"" (several others from the
fr-fr catalog) appears in a Template, they can switch to the french
locale to get an unescaped '.
{{{
In [1]: from django.template import Template, Context, mark_safe
In [2]: c = Context()
In [3]: t = Template('{% load i18n %}{% trans ""Today"" %}')
In [4]: t.render(c)
Out[4]: u""Aujourd'hui""

Note: the ' should be escaped to &#39;

In [5]:
In [6]: c = Context({""today_var"": mark_safe(""Today"")})
In [7]: t = Template('{% load i18n %}{% trans today_var %}')
In [8]: t.render(c)
Out[8]: u""Aujourd'hui""
}}}
I recommend this patch:
{{{
Index: django/utils/translation/trans_real.py
===================================================================
--- django/utils/translation/trans_real.py      (revision 14499)
+++ django/utils/translation/trans_real.py      (working copy)
@@ -9,7 +9,6 @@
 from cStringIO import StringIO

 from django.utils.importlib import import_module
-from django.utils.safestring import mark_safe, SafeData
 from django.utils.thread_support import currentThread

 # Translations are cached in a dictionary for every language+app tuple.
@@ -272,8 +271,7 @@
            from django.conf import settings
            _default = translation(settings.LANGUAGE_CODE)
        result = getattr(_default, translation_function)(eol_message)
-    if isinstance(message, SafeData):
-        return mark_safe(result)
+    # The result of a i18n call is not safe.
    return result

}}}
Result:
{{{
In [1]: from django.template import Template, Context, mark_safe
In [2]: c = Context()
In [3]: t = Template('{% load i18n %}{% trans ""Today"" %}')
In [4]: t.render(c)
Out[4]: u'Aujourd&#39;hui'
In [5]:
In [6]: c = Context({""today_var"": mark_safe(""Today"")})
In [7]: t = Template('{% load i18n %}{% trans today_var %}')
In [8]: t.render(c)
Out[8]: u'Aujourd&#39;hui'
}}}
Additionally, the documentation should be updated to say that strings
marked for translation in templates should not be marked as safe:
{{{
{% trans ""Today &amp; Tomorrow""|safe|upper %} // Looks safe, but gets
translated to French with a '.
}}}
This is only actually safe if i18n is not used, which is why
trans_null still has the ifinstance(SafeData) stuff.

With the patch above and the template {% trans today_and_tomo_var %}

If USE_I18N is off:
{{{
context.insert(""today_and_tomo_var"", mark_safe(""Today &amp; Tomorrow""))

// Ok renders ""Today &amp; Tomorrow""
}}}
If USE_I18N is on:
{{{
context.insert(""today_and_tomo_var"", mark_safe(""Today &amp; Tomorrow""))

// Not Ok. Renders ""Today &amp;amp; Tomorrow"" because the safe-ness is removed.
}}}
To solve that django users would need to be advised *not* to
pre-mark_safe translatable strings before putting them in the Context
*if* USE_I18N is true.

If USE_I18N is on:
{{{
context.insert(""today_and_tomo_var"", ""Today & Tomorrow"")
// Ok. Renders ""Today &amp; Tomorrow"" because
_render_value_in_context escapes the non-safe data.
}}}

The many ways strings could be dealt with make this a tricky issue to solve."	Bug	closed	Documentation	dev	Normal	fixed		Claude Paroz d1b	Accepted	1	0	0	0	0	0
