nexu-io/open-design · error · Error
srcdoc attributes are not supported in live artifact preview
Error message
srcdoc attributes are not supported in live artifact previews
What it means
Thrown by validateHtmlTemplateV1Security when the template matches /\bsrcdoc\s*=/i — a srcdoc attribute anywhere in the markup. srcdoc is the inline-HTML delivery channel for iframes and is blocked independently of the iframe tag itself, so that even an iframe-less element carrying srcdoc (or a future element using the attribute) cannot smuggle HTML into a nested browsing context.
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 srcdoc attribute; render content inline in the template body instead.
- If you need nested HTML, it must be authored directly in the template (subject to the same security scan), not passed as a string attribute.
Example fix
// before
<template><div srcdoc='{{data.html}}'></div></template>
// after
<template><div>{{data.html}}</div></template> Defensive patterns
Strategy: validation
Validate before calling
function assertNoSrcdoc(html: string): void {
if (/\bsrcdoc\s*=/i.test(html)) throw new Error('srcdoc attribute not allowed');
} Type guard
function isSrcdocFree(html: string): boolean {
return !/\bsrcdoc\s*=/i.test(html);
} Try / catch
try { validateHtmlTemplateV1Security(tpl); } catch (e) { throw e; } Prevention
- Render nested HTML inline in the template body, not via srcdoc.
- Scan committed templates for the srcdoc attribute in CI.
- Remember the filter keys on the attribute, so refactoring the element won't help.
When it happens
Trigger: Any attribute written as srcdoc=... on any element, including <div srcdoc=...>, <iframe srcdoc='...'>, or quoted/unquoted forms; also matches inside text content if it happens to look like the attribute assignment.
Common situations: Model embeds an iframe using srcdoc instead of src to dodge the iframe-element check; developer copies an old embed snippet that used srcdoc; misunderstanding that the filter keys on the attribute, not the element.
Related errors
- event handler attributes are not supported in live artifact
- script elements are not supported in live artifact previews
- iframe elements are not supported in live artifact previews
- javascript: URLs are not supported in live artifact previews
- raw HTML insertion directives are not supported
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/04b6800effba3053.
Report an issue: GitHub.