chirp-ui templates use | safe in specific contexts. This document classifies each occurrence and explains the risk model.
| Template | Count | Pattern | Classification | Notes |
|---|---|---|---|---|
forms.html |
6 | {{ attrs | safe }} |
Needs guard | attrs is a raw string escape hatch for HTMX/data attributes. Callers must not pass user-controlled content. Prefer attrs_map (dict) which goes through html_attrs and is escaped. |
dnd.html |
6 | {{ attrs | safe }} |
Needs guard | Same pattern — attrs from html_attrs filter. When attrs is a dict, html_attrs escapes keys/values. When attrs is a raw string, it passes through unescaped. |
fragment_island.html |
2 | {{ attrs | safe }} |
Needs guard | Same pattern. |
sortable_list.html |
1 | {{ attrs | safe }} |
Needs guard | Same pattern. |
wizard_form.html |
1 | {{ attrs | safe }} |
Needs guard | Same pattern. |
layout.html |
1 | {{ meta | safe }} |
Low | Meta line (e.g. config path). Typically internal, not user-facing. Callers should not pass untrusted content. |
streaming.html |
1 | {{ content | markdown | safe }} |
Low | Markdown output is pre-sanitized by Kida's markdown filter. Content should be from trusted sources. |
- Mapping input: Keys and values are escaped via
html.escape(). Safe for structured attrs (e.g.{"hx-post": "/x", "data-id": "123"}). - Raw string input: Passed through unescaped. Intended for legacy escape hatches (e.g.
attrs='hx-get="/q" hx-target="#r"'). Callers must not pass user-controlled or untrusted strings.
- Prefer
attrs_mapoverattrswhen passing HTMX or data attributes.attrs_mapis escaped. - Never pass user input to
attrsormetawithout sanitization. - Streaming content: Ensure
contentinstreaming.htmlcomes from trusted sources (e.g. server-generated markdown, not raw user input without sanitization).
See tests/test_filters.py — TestHtmlAttrsXss verifies that:
- Mapping input escapes event handlers, script tags, and encoded payloads.
- Raw string input is documented as pass-through (caller responsibility).