(Follow up to ticket 33631, where I was asked to discuss this here)
Short summary: The documentation gives this example usage of blocktranslate asvar:
{% blocktranslate asvar the_title %}The title is {{ title }}.{% endblocktranslate %}
And then uses {{ the_title }} in the rest of the template. This example is broken regarding HTML character escaping, because the_title is a str instead of a SafeString. Thus, any further use of {{ the_title }} will lead to double-escaping as long as {{ title }} produced any characters that would be changed by HTML escaping.
In the ticket, we considered whether blocktranslate asvar should return a SafeString instead, which I think it should.
However the ticket was closed as wontfix,
- claiming that it was not clear whether the output assigned to
the_titlecould reliably be marked safe and - asking me to rather use
{{ the_title|safe }}in any following usage.
I think both these points are wrong or misleading:
-
If I removed the
asvarpart, the output would be rendered without additional escaping, so theblocktranslateresult is already implicitly marked safe. Only when I add theasvarargument, because the result is then stored in astrinstead of being rendered, this information gets lost. Consider this code:from django.template import Template, Context template_content = "{% blocktranslate %}Title: &{{ title }}{% endblocktranslate %}" rendered = Template(template_content).render(Context({"title": "amp; & Title"})) assert "Title: & & Title" in rendered # assertion successfulNotice that the inner
&is escaped exactly once, and the html-escape character&that is formed accidentally, is kept exactly as is, without the additional escaping.I argue that these two templates should produce exactly the same output (which is also what the example in the documentation implies), but they don’t:
{% blocktranslate asvar the_title %}Title: &{{ title }}{% endblocktranslate %}{{ the_title }}{% blocktranslate %}Title: &{{ title }}{% endblocktranslate %} -
Obviously, the example from the documentation is a toy-example. In a real-world scenario, you’d have usages much later, or even in different (included) files. For XSS safety, strings should be marked safe at the source whenever possible, so code auditors can directly reason about correctness and safety. Storing the string marked as unsafe and expecting all later uses to use the
|safetemplate tag is a XSS vulnerability waiting to happen.
Note that any workaround we ask users to apply here (such as manually adding |safe on later uses, or computing the title in the view, or something else) basically means that we disagree with the (very sane) assumptions that the template in the documentation makes.