nexu-io/open-design · error · Error
script elements are not supported in live artifact previews
Error message
script elements are not supported in live artifact previews
What it means
Thrown by validateHtmlTemplateV1Security when the template HTML matches /<\s*script\b/i — an opening <script> tag in any case, with any whitespace. Live artifact previews are server-rendered into static HTML and sandboxed; client-side script execution is forbidden, so any <script> element is rejected before interpolation to prevent script injection.
Source
Thrown at apps/daemon/src/live-artifacts/render.ts:34
const TEMPLATE_INTERPOLATION = /{{\s*([^{}]+?)\s*}}/g;
const RAW_TEMPLATE_INTERPOLATION = /{{{[^{}]*}}}|{{\s*&[^{}]*}}/;
const TEMPLATE_PATH = /^(?:data|[A-Za-z_][A-Za-z0-9_]*)(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))*$/;
// `data-od-repeat="item in data.items"` — one loop variable over one `data.*` array.
const REPEAT_DIRECTIVE = /\s*\bdata-od-repeat\s*=\s*"([^"]*)"/i;
const REPEAT_DIRECTIVE_SPEC = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s+in\s+(data(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))*)\s*$/;
const EXECUTABLE_TEMPLATE_PATTERNS: Array<{ pattern: RegExp; message: string }> = [
{ pattern: /<\s*script\b/i, message: 'script elements are not supported in live artifact previews' },
{ pattern: /<\s*iframe\b/i, message: 'iframe elements are not supported in live artifact previews' },
{ pattern: /\bsrcdoc\s*=/i, message: 'srcdoc attributes are not supported in live artifact previews' },
{ pattern: /\son[a-z][a-z0-9_-]*\s*=/i, message: 'event handler attributes are not supported in live artifact previews' },
{ pattern: /(?:href|src|action|formaction)\s*=\s*['"]?\s*javascript\s*:/i, message: 'javascript: URLs are not supported in live artifact previews' },
{ pattern: /\bdata-od-(?:html|raw|bind-html)\b/i, message: 'raw HTML insertion directives are not supported' },
];
export function validateHtmlTemplateV1Security(templateHtml: string): void {
for (const { pattern, message } of EXECUTABLE_TEMPLATE_PATTERNS) {
if (pattern.test(templateHtml)) throw new Error(message);
}
}
export function escapeHtmlTemplateValue(value: unknown): string {
return String(value)
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", ''');
}
/**
* A binding resolver for one scope. Given a trimmed binding path (e.g.
* `data.title` or a loop variable path like `item.label`) it returns the
* already-escaped scalar string to substitute, or throws for an unsupported
* path. Loop scopes delegate non-matching heads (including `data.*`) to their
* parent so global bindings keep working inside a repeat.View on GitHub (pinned to 5be4028344)
Solutions
- Remove the <script> tag entirely; live artifacts do not execute JavaScript.
- Move any client-side logic to a real web app; live artifacts only display server-rendered data.
- If you need dynamic behavior, request it as a new template directive — do not try to bypass the filter.
Example fix
// before
<template><div>{{data.title}}</div><script>console.log('hi')</script></template>
// after
<template><div>{{data.title}}</div></template> Defensive patterns
Strategy: validation
Validate before calling
function sanitizeTemplate(html: string): string {
if (/<\s*script\b/i.test(html)) throw new Error('script tags not allowed');
return html;
}
// or strip: html.replace(/<\s*script\b[\s\S]*?<\/script>/ig, '') Type guard
function hasNoScriptTag(html: string): boolean {
return !/<\s*script\b/i.test(html);
} Try / catch
try { validateHtmlTemplateV1Security(tpl); } catch (e) { /* reject template, log message */ throw e; } Prevention
- Treat templates as data, not as full HTML documents.
- Run validateHtmlTemplateV1Security in your authoring UI before persisting a template.
- Strip scripts at authoring time; never rely on runtime catch alone.
When it happens
Trigger: Template contains <script>alert(1)</script>, <script src=...>, <SCRIPT>, or < script> (whitespace before tag name). Even a script tag inside an HTML comment or a string literal will match because the scan is plain regex over the raw template.
Common situations: Model trained on web tutorials inserts analytics/tracking scripts; developer copies a CodePen snippet that includes inline JS; misunderstanding that live artifacts are static previews, not full pages; intentionally testing the security filter.
Related errors
- iframe elements are not supported in live artifact previews
- raw template interpolation is not supported
- srcdoc attributes are not supported in live artifact preview
- event handler attributes are not supported in live artifact
- javascript: URLs are not supported in live artifact previews
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/87da1d17252f768b.
Report an issue: GitHub.