Every security aspects of allow_unsafe_html


Based on my experience, achieving advanced formatting in a Streamlit app is possible when the allow_unsafe_html tag is set to True, which could potentially lead to security problems and vulnerabilities.

However, what if the Streamlit app is hosted on a server where encryption and other security aspects are managed? For instance, through NGINX configuration, the site employs Let’s Encrypt, and all user inputs are sanitized.

As I am relatively new to this topic, I am eager to understand under what circumstances we can allow unsafe HTML, provided that the site is protected through other tools (such as NGINX configuration, Let’s Encrypt, firewall settings, user input sanitation).

I would greatly appreciate detailed insights on these aspects. The reason being, I’d like my Streamlit app to adhere to ISO 27000 standards while still utilizing more advanced styling elements. OS: AlmaLinux 9

Thank you for your help and detailed explanation!

Does somebody can elaborate for this topic pls? Thanks a lot!

I am super curious

That is a very broad and complex topic. What makes you think that our answers here would help you to comply with 27k standards? What do they say about rendering user-provided HTML?

Hi Goyo,

My firewall and Nginx, along with input sanitization, take care of most vulnerabilities. I’m not an expert in security, and I don’t aim to fulfill every ISO27K requirement. I will try to ask more concrete questions through examples.

Here are my security headers

# Security headers for the entire site
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self';";
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

  1. Example: Adding HTML with unsafe_allow_html
st.markdown("<h1 align='center'>Welcome to My Site</h1>", unsafe_allow_html=True)
  • Does this mean an XSS attack is possible? However, the Nginx headers should prevent it, right?
  1. Example: Customized CSS Style Buttons
st.button("Save", type="primary"):

button[kind="primary"] {
    background-color: rgb(162, 194, 201);
    width: 200px;
    box-shadow: 0 4px 14px 0 rgba(0, 0, 0, 0.25);
    border: none;
    transition: color 1s ease, background-color 1s ease;  /* Smooth transition for color change */
    color: black;

  • Can the current security headers prevent attacks in this scenario?
  1. Example: Loading Custom Styles
hide_streamlit_style = """
                div[data-testid="stDecoration"] {
                visibility: hidden;
                height: 0%;
                position: fixed;
                div[data-testid="stStatusWidget"] {
                visibility: hidden;
                height: 0%;
                position: fixed;

st.markdown(hide_streamlit_style, unsafe_allow_html=True)

  • Can the current security headers prevent attacks in this scenario?

Overall, I would like to know if the current Nginx headers allow me to safely add customized CSS styles to my page. I don’t plan to add JavaScript functions or anything similar. With regular security scans on the server I ensures the security by the way.

I hope my questions are clear. Thank you for your assistance.

I am not really familiar with HTTP headers and I am far from being an expert too. That said, I don’t think any of your examples pose an XSS risk by itself, since no untrusted content is involved.

The issue with, let’s say, your example 3 is that, at a later time, somebody may change hide_streamlit_style from a hardcoded string to a dynamically generated one, without realizing the security implications of doing that.

Thanks! It would be helpful to read an article about best practices for using the unsafe_allow_html tag safely, with examples. Specifically, it would be great to understand what it can and cannot do, how to use it for CSS styling, and any other relevant guidelines.

It is just the best practices that you would follow when writing HTML by any other means, nothing streamlit-specific.