> get_data_from_data_attribute({{ data|to_json }});

This constitutes an injection vulnerability that can be demonstrated with string "alert(1<2)".</p><p>If you want to inject arbitrary strings into a script tag, you need to reach for some more exotic escapes, starting with things like → <\/script> or \u003c/script>. But I’m not going to give you a complete solution because I don’t want you to think this is a good idea. (But if you really want to know: look at the script data state in the HTML spec, and follow the parser. All up, you could do it two different ways, one requiring three things and the other two, though one of the two/three is impossible after JSON encoding.)

People often treat auto-escaping template languages as safe to do anything in, but they’re just not if you use HTML syntax—there are quite a few hazards to be aware of. Here you disabled auto-escaping (mark_safe in the to_json body) because the auto-escaping broke things in one way, but it introduced another vulnerability. For sanity in this context, you need to use XML syntax (by serving with the MIME type application/xhtml+xml), though some JavaScript libraries might misbehave due to side-effects if they make bad assumptions, and third-party templates might not be designed for XML syntax. (All up, I don’t generally recommend using XML syntax, though it’s a close thing.)

Fun fact: you can actually use entity encoding in JavaScript in the HTML syntax… by using the SVG script tag instead of the HTML one:

  alert(1&lt;2)
This is an excellent point; I should have addressed safety in my article. I'll point out that in my use case, I'm using `safe` on data I create and not any user-generated data.

You should never use `safe` on user data unless you use something like bleach (https://github.com/mozilla/bleach) to sanitize the data. Even then, you should use caution.