Back to blog

How a Sandboxed HTML Preview Protects the Host Page

A practical explanation of iframe sandboxing, opaque origins, srcdoc, and the boundaries a code playground must enforce.

Aug 5, 2026ShowYourCode Editorial Team

An HTML playground has an unusual job: it must run code supplied by a visitor without granting that code the privileges of the application around it. Rendering the markup directly into the host document is convenient, but it also lets submitted scripts inspect or change the host DOM. A preview needs a real security boundary.

The iframe is only the beginning

An iframe creates a separate browsing context, but an ordinary same-origin iframe can still interact with its parent. The important control is the sandbox attribute. When allow-same-origin is omitted, the preview receives an opaque origin. Even if the content came from the same application, the browser does not treat it as the same security principal.

That prevents preview code from reading the parent application's cookies, localStorage, or authenticated DOM. ShowYourCode deliberately combines an opaque origin with the narrow allow-scripts capability: scripts can make the demo interactive, but they do not inherit the host session.

<iframe sandbox="allow-scripts" srcdoc="<button>Safe preview</button>"></iframe>

What sandboxing does not solve

Isolation is not moderation. A sandboxed document can still show misleading text, imitate a login form, or attempt network requests. A public platform must therefore separate direct sharing from public recommendation. On ShowYourCode, raw share pages are noindex, and a work enters the Gallery only after editorial review.

The parent should also avoid accepting messages blindly. If postMessage is used for resizing or telemetry, validate the message shape and the expected source window. Never treat an event as trusted merely because it contains the right field names.

A useful review checklist

Before shipping a user-code preview, verify four things:

  1. Submitted HTML never enters the parent DOM.
  2. The sandbox omits privileges the demo does not need.
  3. Authentication tokens are not placed in preview URLs or messages.
  4. Public discovery is gated by moderation rather than raw submission.

Security here is a layered design. The iframe contains technical effects; moderation controls social harm; noindex prevents low-quality submissions from becoming the site's public identity.

Try the isolated preview in the Playground.

Design the boundary from required capabilities

Inventory what the preview must do before choosing sandbox tokens. Static HTML needs no script capability. A JavaScript demo may need allow-scripts, but rarely needs same-origin identity, forms, downloads, popups, or top navigation. Add one capability at a time and keep a short reason beside the configuration. This turns the sandbox from copied syntax into a reviewable security decision.

Keep the frame on an opaque or separate origin. Do not let user-controlled code share the application’s authentication origin. Avoid granting both scripts and same-origin access to content that can manipulate its own frame document. If a separate preview host is used, isolate its cookies, service workers, caches, and error reporting from the main product.

Build a narrow communication channel

Use postMessage only for defined events such as resize, console output, or a user-requested save. Check event.source, allowed origin behavior, a versioned message type, and the exact payload schema. Ignore unknown messages. Never forward arbitrary preview data into DOM insertion, navigation, storage, or privileged API calls.

For height synchronization, cap accepted values and debounce updates. For console forwarding, serialize plain values and limit volume. For navigation requests, show the target outside the frame and require an explicit host-page action. The host should remain the policy decision-maker.

Control network and resource consumption

Sandboxing does not stop the preview from loading trackers, mining CPU, or requesting enormous assets. Apply a Content Security Policy appropriate to the product: often default-src 'none' with explicit allowances for the sources a demo requires. Disable form submission and external connection destinations unless they are essential. Set source length, execution time, and creation-rate limits on the service.

Pause or destroy frames that are off-screen, and provide a manual stop/reset control for runaway code. Expect infinite loops and rapid DOM mutation. Browser isolation protects the host’s data, but the tab can still become unresponsive without operational limits.

Test attacks and ordinary failures

Attempt to access window.parent.document, cookies, localStorage, indexedDB, and service workers. Try top navigation, popup escape, downloads, permission prompts, clipboard writes, external forms, and frame-busting redirects. Confirm that failure is visible and does not trigger privileged host behavior. Repeat the tests in the deployed environment because response headers and origin assignment can differ from local development.

Then test normal work: keyboard focus entering and leaving the frame, screen-reader naming, responsive sizing, errors, slow assets, and reset behavior. A boundary that is secure but impossible to understand still produces a poor user experience.

Pair isolation with publication controls

Technical isolation cannot decide whether a preview infringes copyright, impersonates a service, or displays harmful material. Keep raw user shares out of the search index and advertising inventory. Promote only reviewed examples, put a report control in trusted chrome outside the iframe, record moderation status, and withdraw reported work from curated surfaces pending review.

Document the remaining risk and review the sandbox whenever a new feature requests another token. The strongest implementation is not the one with the longest attribute; it is the one where each capability has an owner, a test, and a clear reason to exist.