Allow HTML (again!) in st.write/st.markdown — but with kwarg toggle
See original GitHub issueUntil last week, st.write and st.markdown used to allow HTML tags. However this is a security risk, as an app author could write unsafe code like this:
import streamlit as st
USER_INPUT = '''
<input type="button" value="click me" onclick="javascript:alert('You have been pwnd. Now I can steal your cookies')"/>
'''
name = st.text_input("What's your name?", USER_INPUT)
st.write(name)
…which is why we turned it off in #95 .
However, many users still depend on this feature, and we’d would like to (1) not break those users and (2) understand why they need HTML so we can come up with better solutions.
So let’s do this for now:
- Keep the default behavior of st.write and st.markdown as: no HTML is allowed
- However, allow the user to pass
unsafe_allow_html=True
to turn on support for HTML
Also, in the pydoc for st.write and st.markdown we should say the following:
While you can use
unsafe_allow_html=True
to turn on support for a limited set of HTML tags inside markdown strings, we strongly advise against it. It is hard to write secure HTML, so by using this argument you may be compromising your users’ security. See this Github issue for more information.Also note that
unsafe_allow_html
is a temporary measure and may be removed from Streamlit any time.If you decide to turn on HTML anyway, we ask you to please post in this [this Github issue](ASK THIAGO FOR LINK) telling us your exact use case. This will help us come up with safe APIs that allow you to do what you want.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:4
- Comments:12 (1 by maintainers)
Top GitHub Comments
I’m commenting on this issue despite it being closed because it seems the security implications of allowing HTML have been misunderstood. Specifically the “Now I can steal your cookies” part is very far fetched.
Any injected javascript will only have access to cookies set against the origin the streamlit page is served from. By definition the author of the app already has access to these cookies because they are the one running the server (if it’s hosted) or the origin is likely localhost if a user is running the app on their machine. In neither case are any valuable cookies exposed. In fact in the later case the author can just use python code to grab all of the user’s cookies from their browser’s file system store, a much more powerful attack.
It is also important to realize that, because the app author has full control over the python side of things, they can at any time serve arbitrary javascript to any user of the app. There is no way to protect against a malicious app author! The only thing you can hope to protect users against is an incompetent app author who ingests data from an untrusted source and doesn’t properly sanitize it.
In order for this to be a danger someone would have to run a streamlit app and deploy it on a domain which has valuable cookies to steal. Then the author of the app or somebody managing to inject data the author hasn’t escape properly will be able to steal cookies from that domain only.
However this could be mitigated in several ways without removing support for HTML. One is to make the streamlit server send a Content Security Policy that blocks inline scripting and all domains not localhost. It can even block segment.com if the user disabled being tracked in the config. It would also force you to include leaflet.js and not fetch it from unpkg.com which is odd anyway.
Another option is to put markdown/html into an iframe which is sandboxed and disallows all javascript execution. This would work if the html is meant purely for display and doesn’t need to be part of the rest of the page.
Removing the ability for app writers to inject HTML (or even script code) seems like a short sighted and very limiting move. It should be disabled by default, but you will never be able to provide all the features people will want and using custom HTML will provide an escape hatch for experienced developers.
Still very new to streamlit & very curious to see if there are other ways to achieve this.
I want to use HTML to a) show links to pictures inside dataframes as actual pictures, b) display links in a clickable format