Secure Practices for Real-Time AI Artifact Rendering and Sandbox Isolation
This guide explains how to safely render AI-generated code, documents, charts, and application prototypes in real time. It covers iframe sandboxing, cross-origin isolation, content security policies, backend execution environments, and secure artifact storage.
1. What Are Artifacts?
In a large language model conversation, code, documents, and charts are often presented only as text. Users then have to copy the output elsewhere to run, format, or review it. Artifacts are a way to place these outputs in a separate window. After the model generates content, the window renders the result immediately. Users can then request changes in natural language, and the window updates accordingly, creating a continuous generate, preview, and revise workflow.
Common artifact types fall into three categories:
- Frontend code and application prototypes — Small web applications built with HTML, CSS, and JavaScript that users can interact with directly in the window.
- Documents and structured content — Markdown documents, as well as flowcharts and architecture diagrams created with Mermaid syntax.
- Data visualizations — Charts generated from data to make trends easier to review quickly.
Artifacts are not suitable for every task. Long-form plain-text writing, one-time questions, and operations that depend on private system permissions are usually better handled directly in the conversation window. If rendering fails, the system should fall back to displaying the source code rather than leaving users with a blank window.
2. Why Generated Code Must Be Isolated
Running model-generated code in a browser introduces several risks. Cross-site scripting (XSS) could allow malicious scripts to execute within the main application. Malicious artifacts might also attempt to read cookies or tokens stored in local storage, or redirect users to phishing pages. For this reason, artifact code must have a clear security boundary from the host application.
Browsers provide two important layers of isolation:
- The
sandboxattribute on an iframe, which restricts the permissions of the embedded page. - Cross-origin isolation, which uses response headers to define how different origins can interact.
These mechanisms address different security concerns and cannot replace one another.
3. iframe Sandboxing: Start with Least Privilege
A recommended embedding pattern is:
<iframesrc="https://artifact-sandbox.example-usercontent.com/a/123"sandbox="allow-scripts"></iframe>
The value of the sandbox attribute is critical. Using only allow-scripts permits scripts to run, while the embedded page receives an opaque origin. As a result, it cannot access the host application’s cookies, localStorage, or DOM.
Do not combine allow-scripts with allow-same-origin. When used together, a sandboxed page may be able to remove its own sandbox restrictions and access same-origin resources, effectively eliminating the isolation boundary.
Other permissions should remain disabled unless they are explicitly required:
allow-formspermits form submissions and should be enabled only when the artifact genuinely needs to submit forms.allow-popupspermits new windows and requires protection against phishing redirects.allow-top-navigationallows the embedded page to change the host page’s address and carries the highest risk. It should generally be avoided.
The sandbox attribute alone is not sufficient. The artifact page’s content security policy must be configured by its own server rather than specified on the iframe element. The csp attribute on an HTML tag is not a standard capability and should not be relied upon.
The correct approach is to have the sandbox domain return an HTTP response header such as:
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'none'
This policy blocks external scripts and network requests while allowing same-origin scripts and inline styles. If an artifact needs to call an external API, requests should be routed through a proxy operated by the main application, with domains allowlisted individually.
Sandbox pages should be deployed under a different registrable domain from the main application, such as a dedicated user-content domain. Using only a separate subdomain is not sufficient, because subdomains can share cookies within the parent domain’s cookie scope.
4. COOP and COEP: Understand Their Boundaries
Cross-Origin-Opener-Policy (COOP) and Cross-Origin-Embedder-Policy (COEP) are often misunderstood as switches that directly enforce process isolation. Their actual responsibilities are different.
The main application can configure the following response headers:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
COOP separates the main application from cross-origin windows and blocks direct references between them through the window object. COEP requires cross-origin resources loaded by the page to explicitly authorize access. Together, these policies can place a page into a cross-origin isolated state, which is required before the browser allows features such as SharedArrayBuffer and high-resolution timers.
These headers do not determine how browser processes are allocated. Process-level separation is handled by the browser’s Site Isolation mechanism, which assigns pages from different sites to different processes. COOP and COEP restrict cross-origin interactions and reduce the precision of some side-channel attacks, but they do not guarantee protection against every side channel. Technical documentation should not claim that they completely prevent user-session theft.
When COEP is enabled, sandbox pages must also comply. Cross-origin resources embedded by those pages need to return:
Cross-Origin-Resource-Policy: cross-origin
Alternatively, they must otherwise meet the relevant COEP requirements. If they do not, the browser may block the resources. Before deployment, check browser console errors in a test environment and verify each blocked resource individually.
5. Backend Execution: Containers Are Not a Complete Isolation Solution
A frontend sandbox can protect code that runs in the browser. When an artifact needs to be compiled, access a database, or execute server-side logic, organizations often use containers. Containers can reduce the impact of a compromise, but they are not a complete security boundary. Container escape vulnerabilities still exist.
An execution environment should meet at least the following requirements:
- Use images from trusted registries, pin image versions, and scan them for vulnerabilities regularly.
- Run as a non-root user, drop unnecessary Linux capabilities, and enable seccomp or AppArmor policies.
- Make the root filesystem read-only, mounting writable space only for temporary directories.
- Disable outbound network access by default and allow access only through an explicit allowlist when required.
- Set limits for CPU, memory, disk usage, and execution time. Forcefully terminate executions that exceed their time limits.
- Use a new instance for every execution, destroy it afterward, and never reuse state from a previous run.
- Record startup events, commands, network access, and abnormal exits for later auditing.
For highly untrusted code, stronger isolation mechanisms such as microVMs may be appropriate. Their trade-offs include longer startup times and higher resource costs.
6. Collaboration and Persistence
Artifacts often need to be persisted. A common approach is to store source code, text, and static pages in object storage. Storage buckets should remain private, with access provided through short-lived signed URLs to prevent artifacts from being publicly enumerated.
