Consider renaming `mark_safe` to `dangerously_trust_html` (etc)

288 views
Skip to first unread message

Stuart Cox

unread,
Jan 28, 2018, 11:14:27 AM1/28/18
to Django developers (Contributions to Django itself)
In my experience, misuse of mark_safe() — i.e. marking stuff safe which isn’t actually safe (e.g. HTML from a rich text input) — is one of the biggest causes of XSS vulnerabilities in Django projects.

The docs warn to be careful, but unfortunately I think Django devs have just got too used to mark_safe() being the way to insert HTML in a template. And it’s easy for something that was safe when it was authored (e.g. calling mark_safe() on a hard-coded string) to be copied / repurposed / adapted into a case which is no longer be safe (e.g. that string replaced with a user-provided value).

Some other frameworks use scary sounding names to help reinforce that there are dangers around similar features, and that this isn’t something you should use in everyday work — e.g. React’s dangerouslySetInnerHTML.

Relatedly, this topic suggested making it more explicit that mark_safe() refers to being safe for use in HTML contexts (rather than JS, CSS, SQL, etc).

Combining the two, it would be great if Django could rename mark_safe() to dangerously_trust_html(), |safe to |dangerously_trust_html, @csrf_exempt to @dangerously_csrf_exempt, etc.

Developers who know what they’re doing with these could then be encouraged to create suitable wrappers which handle their use case safely internally — e.g.:

@register.filter
def sanitize_and_trust_html(value):
    # Safe because we sanitize before trusting
    return dangerously_trust_html(bleach.clean(value))


Douglas Miranda

unread,
Feb 15, 2018, 4:44:54 PM2/15/18
to Django developers (Contributions to Django itself)
I think this can mislead the developers to think mark_safe solves it all.

The forums are full of answers with Use mark_safe; Use htmlfield|safe; 
 
Maybe Django should start warning about mark_safe on the logs, then change the behavior. (Or even deprecate and remove)

Things like this we tend to blame the users, but it's there for using and it says "SAFE".

Josh Smeaton

unread,
Feb 21, 2018, 4:41:15 PM2/21/18
to Django developers (Contributions to Django itself)
I agree that the names are misleading and we should probably provide better names. I'm wary of deprecating the old names because it'll create a lot of churn (some of which would be the right thing to do). Maybe we could just alias and warn when using the old name, leaving a decision on deprecation until some time in the future.

Collin Anderson

unread,
Feb 21, 2018, 4:55:50 PM2/21/18
to django-d...@googlegroups.com
> Maybe we could just alias and warn when using the old name, leaving a decision on deprecation until some time in the future.

I'm a fan of delaying deprecation/removal if we do change it. :)

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/05de4602-5c44-41bf-b675-ab15d69fb46d%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Florian Apolloner

unread,
Feb 22, 2018, 5:08:31 AM2/22/18
to Django developers (Contributions to Django itself)
Yeah, I am also worried about the churn for no gain in my eyes. If users overuse mark_safe, they will overuse dangerously_trust_html too…

Josh Smeaton

unread,
Feb 22, 2018, 7:16:29 AM2/22/18
to Django developers (Contributions to Django itself)
The concern isn't overusing an API. It's not understanding the proper use case for it.

"mark safe" can sound like the API is doing sanitation so it can encourage developers to use it incorrectly. I'm fairly sure I've done this myself.

The intended meaning is "this output is **already** safe" but the name doesn't convey that meaning clearly enough.

What the proposal is designed to do is convey the "I trust this output" meaning of the API. I'm just wary of enforcing users to change code when they already use the API correctly.

Tim Graham

unread,
Feb 22, 2018, 7:59:50 AM2/22/18
to Django developers (Contributions to Django itself)
I don't know that "dangerously_trust_html" is a better name. The argument is supposed to be a string that you know is trusted so there shouldn't be any danger involved. Naming something based on how it could be misused seems odd.

For me, mark_safe() is a fine name, but maybe that preference is from a knowledge of django.utils.safestring internals that most users don't have.

Anthony King

unread,
Feb 22, 2018, 8:10:46 AM2/22/18
to django-d...@googlegroups.com
I entirely agree with renaming `mark_safe`. Though it's name is correct, it doesn't convey the gravity of what this actually does.
However I'm unsure on the `dangerously_trust_html` name. It wouldn't be dangerous to trust the literal "<small>Some Content</small>", for example.

Perhaps it could be something a bit more explicit. `no_escape(string)`?
This assumes that most have at least heard of escaping.


--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

Tom Forbes

unread,
Feb 22, 2018, 8:30:20 AM2/22/18
to django-d...@googlegroups.com
What about just 'trust_html'? The dangerous part is quite context dependent (and a bit of mouth-full), but at the core you are trusting the HTML. Hopefully it follows that you should not trust html with user input that hasn't been escaped.

Adam Johnson

unread,
Feb 22, 2018, 9:07:12 AM2/22/18
to django-d...@googlegroups.com
I am also in favour of a rename without deprecating the old name.

I like 'trust_html' - it's still similarly short but as Tom says it implies more than 'mark_safe' does.


For more options, visit https://groups.google.com/d/optout.



--
Adam

Douglas Miranda

unread,
Feb 22, 2018, 12:40:08 PM2/22/18
to Django developers (Contributions to Django itself)
Yes, people read mark_safe as MAKE_safe, I'm not sure yet, but I'm liking the idea of trust_html, I feel like more developers will understand what they're doing.

Maybe the docs could have more detailed notes about HTML inputs that you want to mark them safe, one thing is trust "<span>" another is trust "{{ post.content }}". Rich text editors play a big part of beginner devs, a lot of people start with Django and don't quite understand Python or Web Security yet, that's just reality.

Django it is not to blame, but I think that's a small change with big impact.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.



--
Adam

Дилян Палаузов

unread,
Feb 22, 2018, 3:31:47 PM2/22/18
to django-d...@googlegroups.com
Hello,

is everybody fine with the documentation of mark_safe?

I think by default people don't come to the idea to use mark_safe
except on occasions, where they notice their output is not the desired
one. Then investigations on rendering to achieve the right output
lead to mark_safe() and by that time the developers have enough
knowledge how the whole stuff works internally.

With this flow there is no danger of misusing mark_safe.

Greetings
Дилян

----- Message from Douglas Miranda <douglasmi...@gmail.com> ---------
Date: Thu, 22 Feb 2018 09:40:08 -0800 (PST)
From: Douglas Miranda <douglasmi...@gmail.com>
Reply-To: django-d...@googlegroups.com
Subject: Re: Consider renaming `mark_safe` to `dangerously_trust_html` (etc)
To: "Django developers (Contributions to Django itself)"
<django-d...@googlegroups.com>


> Yes, people read *mark_safe* as *MAKE_safe*, I'm not sure yet, but I'm
> liking the idea of *trust_html*, I feel like more developers will
> understand what they're doing.
>
> Maybe the docs could have more detailed notes about HTML inputs that you
> want to mark them safe, one thing is trust "<span>" another is trust "{{
> post.content }}". Rich text editors play a big part of beginner devs, a lot
> of people start with Django and don't quite understand Python or Web
> Security yet, that's just reality.
>
> Django it is not to blame, but I think that's a small change with big
> impact.
>
>
> On Thursday, February 22, 2018 at 10:07:12 AM UTC-4, Adam Johnson wrote:
>>
>> I am also in favour of a rename without deprecating the old name.
>>
>> I like 'trust_html' - it's still similarly short but as Tom says it
>> implies more than 'mark_safe' does.
>>
>> On 22 February 2018 at 08:30, Tom Forbes <t...@tomforb.es <javascript:>>
>> wrote:
>>
>>> What about just 'trust_html'? The dangerous part is quite context
>>> dependent (and a bit of mouth-full), but at the core you are trusting the
>>> HTML. Hopefully it follows that you should not trust html with user input
>>> that hasn't been escaped.
>>>
>>>
>>> On 22 Feb 2018 13:10, "Anthony King" <anthon...@gmail.com <javascript:>>
>>> wrote:
>>>
>>> I entirely agree with renaming `mark_safe`. Though it's name is correct,
>>> it doesn't convey the gravity of what this actually does.
>>> However I'm unsure on the `dangerously_trust_html` name. It wouldn't be
>>> dangerous to trust the literal "<small>Some Content</small>", for example.
>>>
>>> Perhaps it could be something a bit more explicit. `no_escape(string)`?
>>> This assumes that most have at least heard of escaping.
>>>
>>>
>>> On 22 February 2018 at 12:16, Josh Smeaton <josh.s...@gmail.com
>>>>>>> which *isn’t* actually safe (e.g. HTML from a rich text input) — is
>>>>>>> one of the biggest causes of XSS vulnerabilities in Django projects.
>>>>>>>
>>>>>>> The docs warn to be careful, but unfortunately I think Django devs
>>>>>>> have just got too used to mark_safe() being *the way* to insert HTML
>>>>>>> in a template. And it’s easy for something that was safe when it was
>>>>>>> authored (e.g. calling mark_safe() on a hard-coded string) to be
>>>>>>> copied / repurposed / adapted into a case which is no longer
>>>>>>> be safe (e.g.
>>>>>>> that string replaced with a user-provided value).
>>>>>>>
>>>>>>> Some other frameworks use scary sounding names to help reinforce that
>>>>>>> there are dangers around similar features, and that this isn’t
>>>>>>> something
>>>>>>> you should use in everyday work — e.g. React’s
>>>>>>> dangerouslySetInnerHTML.
>>>>>>>
>>>>>>> Relatedly, this topic
>>>>>>> <https://groups.google.com/d/msg/django-developers/c4fa2pOcHxo/EtT942WnyiAJ>
>>>>>>> suggested
>>>>>>> making it more explicit that mark_safe() refers to being safe for
>>>>>>> use in *HTML* contexts (rather than JS, CSS, SQL, etc).
>>>>>>>
>>>>>>> Combining the two, it would be great if Django could rename
>>>>>>> mark_safe() to dangerously_trust_html(), |safe to
>>>>>>> |dangerously_trust_html, @csrf_exempt to @dangerously_csrf_exempt,
>>>>>>> etc.
>>>>>>>
>>>>>>> Developers who know what they’re doing with these could then be
>>>>>>> encouraged to create suitable wrappers which handle their use
>>>>>>> case safely
>>>>>>> internally — e.g.:
>>>>>>>
>>>>>>> @register.filter
>>>>>>> def sanitize_and_trust_html(value):
>>>>>>> # Safe because we sanitize before trusting
>>>>>>> return dangerously_trust_html(bleach.clean(value))
>>>>>>>
>>>>>>>
>>>>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Django developers (Contributions to Django itself)" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to django-develop...@googlegroups.com <javascript:>.
>>>> To post to this group, send email to django-d...@googlegroups.com
>>>> <javascript:>.
>>>> <https://groups.google.com/d/msgid/django-developers/db4ac958-89e1-4286-a616-99e9854c9bbb%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "Django developers (Contributions to Django itself)" group.
>>> To unsubscribe from this group and stop receiving emails from it, send an
>>> email to django-develop...@googlegroups.com <javascript:>.
>>> To post to this group, send email to django-d...@googlegroups.com
>>> <javascript:>.
>>> Visit this group at https://groups.google.com/group/django-developers.
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/django-developers/CALs0z1YuC63d6aJ1VEhcnezpCg1NPJYpadcR4-fRRwGDrR4-qw%40mail.gmail.com
>>> <https://groups.google.com/d/msgid/django-developers/CALs0z1YuC63d6aJ1VEhcnezpCg1NPJYpadcR4-fRRwGDrR4-qw%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "Django developers (Contributions to Django itself)" group.
>>> To unsubscribe from this group and stop receiving emails from it, send an
>>> email to django-develop...@googlegroups.com <javascript:>.
>>> To post to this group, send email to django-d...@googlegroups.com
>>> <javascript:>.
>>> Visit this group at https://groups.google.com/group/django-developers.
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/django-developers/CAFNZOJPfw9ybsHOcs%3D9nfORtEJJz9pzKvEM7bRA6BaYwHXW3pQ%40mail.gmail.com
>>> <https://groups.google.com/d/msgid/django-developers/CAFNZOJPfw9ybsHOcs%3D9nfORtEJJz9pzKvEM7bRA6BaYwHXW3pQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>
>>
>> --
>> Adam
>>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to django-develop...@googlegroups.com.
> To post to this group, send email to django-d...@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/ce94677d-b400-4429-882d-4495d58b6f61%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.


----- End message from Douglas Miranda <douglasmi...@gmail.com> -----



Josh Smeaton

unread,
Feb 22, 2018, 3:46:45 PM2/22/18
to Django developers (Contributions to Django itself)
Yes I'm not a fan of the dangerously... names either. I'm still somewhat wary of trust_html which is a verb and could still confuse users in a similar way (does the api make it trustworthy?). I think I'd prefer something more descriptive like trusted_html.

<div>{{ content|trusted_html }}</div>
vs
<div>{{ content|trust_html }}</div>
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.



--
Adam

Josh Smeaton

unread,
Feb 22, 2018, 3:52:04 PM2/22/18
to Django developers (Contributions to Django itself)
Or, since this isn't a template tag (facepalm) 

trusted_html(m.content)
trust_html(m.content) 

Tom Forbes

unread,
Feb 22, 2018, 3:52:06 PM2/22/18
to django-d...@googlegroups.com
You're right, trusted_html is a better name than trust_html. I think either is superior to mark_safe however.

Regarding deprecations, deprecating mark_safe will cause a lot of churn even if the migration path is as simple as a rename. We should keep the old alias around for a long time, but promote the new name wherever possible.

To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.

Florian Apolloner

unread,
Feb 22, 2018, 4:24:50 PM2/22/18
to Django developers (Contributions to Django itself)


On Thursday, February 22, 2018 at 9:52:04 PM UTC+1, Josh Smeaton wrote:
Or, since this isn't a template tag (facepalm) 

Which raises a perfectly valid point: If we were to change this, we will also need to come up with a new name for the "|safe"-filter.

Josh Smeaton

unread,
Feb 22, 2018, 5:36:58 PM2/22/18
to Django developers (Contributions to Django itself)
We could use the same name or just |trusted.

I'm not so concerned with the `safe` tag as it's already an adjective, but I would be ok with an alias for trusted also.

Kamil

unread,
Feb 23, 2018, 7:20:18 AM2/23/18
to Django developers (Contributions to Django itself)
The name "mark_safe" unnecessarily exposes an implementation detail. People who misunderstand this API probably have no idea how this "marking" happens, it would make sense to name this after the *effect* it achieves: "don't process / escape me, I've been sanitized somewhere else".
Any of these would work: "no_escape", "dontescape", "sanitized_elsewhere", etc.

Adam Johnson

unread,
Feb 19, 2020, 4:11:11 AM2/19/20
to django-d...@googlegroups.com

On Fri, 23 Feb 2018 at 08:53, Kamil <harr...@gmail.com> wrote:
The name "mark_safe" unnecessarily exposes an implementation detail. People who misunderstand this API probably have no idea how this "marking" happens, it would make sense to name this after the *effect* it achieves: "don't process / escape me, I've been sanitized somewhere else".
Any of these would work: "no_escape", "dontescape", "sanitized_elsewhere", etc.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

For more options, visit https://groups.google.com/d/optout.


--
Adam

Carlton Gibson

unread,
Feb 19, 2020, 9:20:15 AM2/19/20
to Django developers (Contributions to Django itself)
I've just closed the ticket as wontfix, because I'm not seeing a consensus for the change here. I'm seeing a few Yeahs and a few Mehs. 
That doesn't mean we can't have it, but the procedure is generally agree here before a ticket. 
So can I ask, those wanting this, to make the case here, then we can re-open the ticket if there is a general agreement. 

<opinion open-to-change=true>
FWIW I'm not convinced. The warnings on the mark_safe() docs are pretty clear cut. 
I think users will just use whatever gets their content on the screen, probably knowing it's not safe, but telling themselves 
that they'll come back later. Change the names and that will still be the same. 
There'll just have been a massive load of busywork in between. 

Ideally we'd just ship Bleach &co. That's a battery we could include. 
But we can't really do that, because html5lib is unmaintained, and there's no alternative. 
Whatever effort there is to be spent on this, I'd rather see it spent there. 
</opinion>

Kind Regards,

Carlton

Adam Johnson

unread,
Feb 19, 2020, 11:56:51 AM2/19/20
to django-d...@googlegroups.com
Sorry I was a bit keen after a reminder of the thread by Josh Smeaton on reddit. I skimmed again and it felt like there was consensus on some kind of rename, and it had moved to decision on the name. I guess I'm also sick of fixing this in client projects :)

I think your concerns are fair and well-reasoned as always Carlton. You've convinced me this isn't worth it.

I'd love to see a bleach "battery" too. Was not aware of html5lib going unmaintained - it does highlight that there's a lot to do elsewhere in the ecosystem.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.


--
Adam

Josh Smeaton

unread,
Feb 19, 2020, 3:36:39 PM2/19/20
to django-d...@googlegroups.com
My thoughts: 

Use and promote a different name that does not make it sound like Django is making the string safe for you. 

Alias the new name to the old names to prevent churn.

Remove all references of the old name from the docs. 

What the name should be, meh. 

You received this message because you are subscribed to a topic in the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-developers/AvgxWR-0VrE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAMyDDM091w46Pt%3DkiAbU5qgTxOj-_BE5hqz7qZeNNBGkG-RX_A%40mail.gmail.com.

Kye Russell

unread,
Feb 19, 2020, 6:16:12 PM2/19/20
to Adam Johnson, django-d...@googlegroups.com
Personally I think that the current name does a fairly good job of conveying the effect, and this is coming from someone who doesn’t explicitly understand the internal process and is merely inferring it.

However my anecdote doesn’t negate what we all see around the internet, so I suppose it can be improved.

I am a strong -1 on adding words like “dangerously” to the method name. I feel that method names are not the place for warnings like that. I do not like the precedent that it sets for other potentially unsafe methods within the Django codebase, and i believe that it’d result in unnecessarily verbose project code.

Kye Russell
Sent from my iPhone

> On 19 Feb 2020, at 5:11 pm, Adam Johnson <m...@adamj.eu> wrote:
>

Josh Smeaton

unread,
Feb 19, 2020, 6:22:07 PM2/19/20
to Django developers (Contributions to Django itself)
I agree that "dangerously" doesn't and shouldn't be in the name - it's unnecessarily verbose.

I think a name like "no_escape" ,or similar, conveys the meaning properly and is no more verbose than mark_safe.
Reply all
Reply to author
Forward
0 new messages