Kida auto-escapes output by default to prevent XSS vulnerabilities.
Autoescape
Withautoescape=True(default), output is HTML-escaped:
env = Environment(autoescape=True)
template = env.from_string("{{ content }}")
html = template.render(content="<script>alert('xss')</script>")
# Output: <script>alert('xss')</script>
Special characters are replaced:
| Character | Escaped |
|---|---|
< |
< |
> |
> |
& |
& |
" |
" |
' |
' |
Disable Autoescape
For specific templates:
# Callable autoescape
def should_escape(template_name):
if template_name is None:
return True
return template_name.endswith(".html")
env = Environment(autoescape=should_escape)
Globally (not recommended):
env = Environment(autoescape=False)
Safe Filter
Mark content as trusted HTML:
{{ html_content | safe }}
With optional reason for code review:
{{ cms_block | safe(reason="sanitized by bleach library") }}
{{ admin_html | safe(reason="admin-only content") }}
Markup Class
Create safe HTML in Python:
from kida import Markup
# String marked as safe
safe_html = Markup("<b>Bold</b>")
template.render(content=safe_html) # Not escaped
Markup Operations
# Concatenation escapes unsafe strings
safe = Markup("<b>")
result = safe + "<script>" # <b><script>
result = safe + Markup("<i>") # <b><i>
# Format escapes arguments
Markup("<p>{}</p>").format("<script>")
# <p><script></p>
Escape Function
from kida import Markup
# Escape a string
escaped = Markup.escape("<script>")
# <script>
Common Patterns
Pre-Sanitized Content
When content is already sanitized:
import bleach
cleaned = bleach.clean(user_html, tags=["b", "i", "a"])
template.render(content=Markup(cleaned))
Rendered Markdown
import markdown
html = markdown.markdown(source)
template.render(content=Markup(html))
HTML in JSON
Thetojsonfilter escapes for JavaScript:
<script>
const data = {{ user_data | tojson }};
</script>
Security Best Practices
Always Use Autoescape
# ✅ Autoescape on (default)
env = Environment(autoescape=True)
# ❌ Never disable globally
env = Environment(autoescape=False)
AuditsafeUsage
{# ✅ Document why it's safe #}
{{ content | safe(reason="sanitized by bleach") }}
{# ❌ Unmarked safe usage #}
{{ user_input | safe }}
Validate Content
# ✅ Sanitize before marking safe
cleaned = bleach.clean(content, tags=ALLOWED_TAGS)
Markup(cleaned)
# ❌ Never mark user input safe directly
Markup(request.form["content"]) # XSS vulnerability!
Escape Filter
Explicitly escape content:
{{ content | escape }}
{{ content | e }} {# Short alias #}
Useful when autoescape is disabled for a template.
See Also
- Filter Reference — escape, safe, striptags
- Variables — Output expressions
- Error Handling — Debug template issues