Safely serializing complex values to HTML element attributes

When I have to transfer complex values (e.g. a list of dicts) through a Django template to the front end, I typically use json_script to try and prevent XSS vectors.

Recently, I started using lit-element, which has a neat way of pulling attribute values from your custom elements and providing them as properties to your component. You can say:

<my-element items="{{ serialized array of items }}"></my-element>

Then lit-element will take whatever string value is passed to the items attribute and call JSON.parse() on it, so I need a way of serializing my value to JSON.

Since that is relatively trivial in itself, my initial idea was to write a custom template filter and try to match how json_script escapes values. But then I read the source for that function and it explicitly states:

Escape all the HTML/XML special characters with their unicode escapes, so value is safe to be output anywhere except for inside a tag attribute.

This sounds like attribute values are potentially a more serious XSS vector. So I guess my question is - how to serialize data (in Django/Python) to JSON so it's safe for use in tag attribute values?

1 answer

  • answered 2020-06-02 10:49 tim-mccurrach

    I think the reason it says can be used anywhere apart from attributes is that this function doesn't escape speechmarks, this means you would be able to close an attribute and start a new one easily. Django provides the escapejs template tag that escapes speech marks as well.

    This function is in the same source that you linked in your question. Following the approach used there should be safe.