Opened 2 years ago

Last modified 2 years ago

#29602 new Bug

Jinja2's forceescape filter doesn't work on Django's safe strings

Reported by: Richard Eames Owned by: nobody
Component: Utilities Version: 2.0
Severity: Normal Keywords:
Cc: Claude Paroz Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


Not sure if this is a Django bug, jinja bug, or something I need to change for upgrading to Django 2.0, but since it was a Django commit causes it, I'm reporting here first.

I recently upgraded to Django 2.0, and shortly after had a complaint from one of our users about a page not displaying correctly. I tracked down the issue to a usage of Jinja's forceescape filter.

My usage is that we're displaying a preview of an email that will be sent out, and we do this by using the srcdoc attribute of iframe, so our code looks like:

<iframe srcdoc="{{ rendered_email | forceescape }}"></iframe>

The rendered_email variable is from a call to get_template(template_name).render(ctx), which returns a SafeString object. Which makes sense since a rendered template should be html. And since I want to display the email inside of html again, it needs to be re-escape, logically with the forceescape filter.

However, a change from this ticket/this commit causes the forceescape filter to fail on the jinja side. forcescape calls str() on it's argument to remove the "safety", then re-escapes it, however, the aforementioned commit allow SafeString to bypass the assumption that jinja makes when calling str().

Change History (3)

comment:1 Changed 2 years ago by Tim Graham

Cc: Claude Paroz added
Summary: Django 2.0 breaks interop with Jinja2 forceescape filterJinja2's forceescape filter doesn't work on Django's safe strings

jinja.filters.do_forceescape() uses markupsafe.escape(). Since str(SafeText) now returns the SafeText, the hasattr(s, '__html__') check in escape() returns True and no escaping happens.

I think it's a legitimate issue as the behavior is certainly unexpected (SafeText with the Django template language's force_escape filter works as you would expect), however, I'm not sure what the best way forward is as it's a bit late in the Django 2.0 lifecycle to revert the original change.

comment:2 Changed 2 years ago by Richard Eames

I agree, it is a bit late in the 2.0 life cycle to revert it; but a note in the 2.0 change log would be very helpful for anyone else that's doing a late upgrade like I was (while upgrading I was checking everything in the release notes against our code base). I also assume it's too late in the 2.1 release cycle to fix in some way?

As a work around, I should either be able to use django's force_escape, or manually wrap the variable in Jinja's MarkUp() function so that it works with Jinja's forceescape.

Last edited 2 years ago by Richard Eames (previous) (diff)

comment:3 Changed 2 years ago by Tim Graham

Component: Template systemUtilities
Triage Stage: UnreviewedAccepted

Generally we don't document bugs in the release notes. :-)

It will be interesting to hear Claude's opinion on this issue.

Note: See TracTickets for help on using tickets.
Back to Top