Skip to content

Security and Escaping

oldmangan edited this page Oct 6, 2026 · 1 revision

wapyt renders model output, remote data and user input, so these rules matter.

What you must escape

API Inserts Your job
Layout.attach_html, CellConfig(html=...) raw HTML html.escape(value, quote=True) every interpolated value
TabConfig(html=...), TabWidget.attach_html raw HTML same
ModalWindow.set_content(markup) raw HTML same
ResourceBoardConfig.detail_template escaped {placeholders} nothing, unless you use a …Html key, which is raw
CardPanel descriptor templates escaped into html; text is set as text nothing
Widget labels, titles, cells, tree nodes, form values text nothing

Built in

  • Widgets put text into the DOM with textContent. Markup uses innerHTML only with escapeHtml() on every interpolated value.
  • Chat renders markdown with its own escaping renderer. It uses marked only when DOMPurify is also on the page, because marked passes raw HTML through.
  • Chat artifact chips are the one unescaped fragment, and carry a per-widget nonce, so model output that only looks like a chip is still escaped.
  • Artifact previews run in <iframe sandbox="allow-scripts">. Never add allow-same-origin: with allow-scripts it cancels the sandbox.

Validation is not security

Form validation helps the person typing. The BFF must revalidate everything it receives; show its errors with form.set_error(...).

Browser permissions

pyTincture denies microphone and camera by default (Permissions-Policy: microphone=()). Chat voice input needs PYTINCTURE_ALLOW_MICROPHONE=1 and a secure context.

Clone this wiki locally