AI Safety
·IdenticAPI

How to Safely Render AI-Generated HTML

Rendering model-generated HTML requires sanitization, CSP, and output moderation. Learn safe patterns for chat UIs and rich-text features.

To safely render AI-generated HTML, treat every model-produced tag as potentially hostile: moderate the completion before display, sanitize against a strict allowlist, encode when plain text suffices, and enforce Content-Security-Policy (CSP) so executable markup cannot compromise users even if a filter misses something.

Rich chat, email previews, and document assistants often ask models for formatted output — which invites <script>, event handlers, javascript: URLs, and nested SVG attacks. Safe rendering is non-negotiable for web-facing LLM products.

Why AI-generated HTML is high risk

Models optimize for helpful formatting, not your security model. Given benign prompts, they may still emit:

  • <img onerror=...> and <svg/onload=...> patterns
  • <a href="javascript:..."> links
  • <iframe src="..."> embedding untrusted origins
  • <style> blocks with expression/import tricks (legacy browsers)
  • Markdown that expands to raw HTML in your pipeline

Because the HTML originates from your application’s assistant, browsers and users treat it as more trustworthy than random user comments — increasing impact of stored XSS. This is a form of improper output handling.

Defense in depth

Use four layers together:

LLM HTML/Markdown → Output moderation → Sanitizer → CSP → DOM

Skipping any layer increases exposure.

Layer 1: Output moderation

Run AI Output Safety on the full string before sanitization:

curl -X POST https://www.identicapi.com/api/v1/security/output-safety \
  -H "Authorization: Bearer idapi_test_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"text": "<p>Invoice attached</p><img src=x onerror=alert(1)>"}'

Route on verdict (safe, suspicious, unsafe), risk, findings, and reasons. Block or review high-risk content before it enters your HTML pipeline. Prototype with the AI Output Safety Checker; see documentation.

Moderation catches many patterns early but is not a HTML parser — continue to sanitize.

Layer 2: Prefer plain text or Markdown-to-safe subset

Default chat UIs to escaped plain text. If you need formatting:

  • Render Markdown with a library that disables raw HTML by default
  • Do not pass allowDangerousHtml: true equivalents

When HTML is required, generate it server-side through a sanitizer — not client-side trust of model strings.

Layer 3: HTML sanitization

Use a maintained sanitizer (DOMPurify in browser; isomorphic or server-side equivalents in Node/Python). Configure an explicit allowlist:

AllowBlock
p, br, strong, em, ul, ol, li, code, prescript, iframe, object, embed
a[href] with http(s) onlyjavascript:, data: URLs in href
code, pre for snippetsEvent attributes (onclick, onerror, …)
style unless strictly needed

Strip data attributes and unknown tags. Re-sanitize on every render path — including cached messages loaded from database.

Layer 4: Content-Security-Policy

Set CSP on pages that display AI chat:

Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

Adjust for your asset CDN. CSP limits damage if sanitizer or moderation misses a vector. Details overlap with XSS prevention for AI content.

Safe rendering flow (Next.js and others)

Server-side pattern:

  1. Receive model completion in Route Handler
  2. Call output safety API
  3. If allowed, sanitize HTML server-side
  4. Return sanitized HTML or structured AST to client
  5. Client renders without dangerouslySetInnerHTML when possible — use a vetted renderer

Full Next.js example: Output Safety in Next.js.

Markdown-specific pitfalls

Common unsafe chain:

Model → Markdown with embedded HTML → markdown-it with html:true → XSS

Mitigations:

  • Disable raw HTML in Markdown parser
  • Post-process Markdown output through sanitizer
  • Moderate before Markdown conversion (attack strings may span Markdown/HTML boundaries)

Synthetic unsafe examples (do not use in production DOM)

<!-- Event handler -->
<b onmouseover=alert(1)>hover me</b>

<!-- JavaScript URL -->
<a href="javascript:alert(document.cookie)">click</a>

<!-- Meta refresh in sanitizer bypass attempts -->
<meta http-equiv="refresh" content="0;url=https://attacker.example">

Test these in staging with moderation + sanitizer + CSP enabled — expect blocks at one or more layers.

Storage considerations

If you persist assistant HTML:

  • Store sanitized form, or store raw with versioned sanitizer re-run on read
  • Re-moderate when displaying old messages after policy updates
  • Prevent other users' viewers from interpreting stored HTML in admin panels without encoding

Treat stored model output as untrusted on every read path.

When not to render HTML at all

Many products need formatting without HTML:

  • Use component-based message AST (paragraph, list, link nodes) built from validated JSON, not raw tags
  • Links: validate URL scheme and domain allowlist in application code
  • Code blocks: display in <pre> with text content only

This removes entire XSS classes at the cost of flexibility.

Integration with broader guardrails

Rich text features often coincide with customer-facing bots. Combine:

Limitations

No combination eliminates all risk:

  • Sanitizer bypass research continues — keep dependencies patched
  • Moderation verdicts are probabilistic signals
  • CSP misconfiguration can weaken protections

Document residual risk and maintain incident response for reported XSS in chat.

Quick reference

StepAction
1Moderate completion with AI Output Safety
2Block/review on unsafe / suspicious per policy
3Sanitize with strict allowlist
4Apply CSP on chat pages
5Avoid raw innerHTML / unsanitized Markdown HTML
6Regression-test synthetic XSS payloads in CI

Safe HTML rendering for AI content is a solved engineering pattern — moderation plus sanitizer plus CSP — not a model behavior promise. Implement all three before enabling rich assistant replies in production.

Frequently asked questions

Should I allow AI models to return raw HTML in chat?

Only if you moderate output, sanitize against a strict allowlist, and deploy CSP. Default to plain text or Markdown with raw HTML disabled for simpler, safer chat UIs.

What HTML tags are typically safe to allowlist?

Many products allow structural tags like p, br, strong, em, ul, ol, li, code, and pre, plus anchors with http(s) href only. Block script, iframe, object, embed, event attributes, and javascript: URLs.

Should I sanitize before or after output moderation?

Moderate first to block or review high-risk messages early, then sanitize allowed content before storage and render. Moderation is not a HTML parser; sanitization remains required.

Do I need CSP if I use a sanitizer?

Yes. CSP limits script execution if sanitizer or moderation misses a vector. Use defense in depth rather than relying on a single control.

Related reading