CodePen Embedded Pens: Architecture, Isolation Guarantees, and Operational Verification
An architecture note on CodePen's Embedded Pens: the minimal stateless design, sandbox and CSP trust boundaries, operational verification steps, failure modes, and design change triggers that would require re-evaluating isolation guarantees.
09 Oct 2025, 12:12 UTC

Requirements
CodePen's Embedded Pens feature must allow any website to embed a live, interactive code demonstration without exposing the host page to cross-site scripting (XSS) or data leakage. The requirements are:
- Isolation: User-authored HTML, CSS, and JavaScript must execute in a context that cannot access the embedding page's DOM, cookies, localStorage, or JavaScript namespace.
- Integrity: The embedded code must be served exactly as authored, without injection or modification by the delivery infrastructure.
- Performance: Embed load time should not block the host page's critical rendering path.
- Compatibility: The embed must work across modern browsers without requiring plugins or special user permissions.
These requirements map directly to browser sandboxing primitives: iframe sandbox attributes and Content Security Policy (CSP) headers.
Smallest Suitable Design
The minimal architecture consists of three stateless components:
- Embed script: A tiny JavaScript snippet (≈1 KB gzipped) that the host page includes. It reads a
data-pen-idattribute, constructs a preview URL, and injects aniframewith a hardcoded sandbox attribute string. - Preview service: A stateless HTTP endpoint (
https://cdpn.io/pen/{pen-id}) that resolves the pen ID to a set of static assets (HTML, CSS, JS) and returns an HTML document with CSP headers. - CDN: A content delivery network that caches and serves the static assets referenced by the preview document.
The embed script does no authentication, no dynamic rendering, and no postMessage communication. It only creates an iframe element with:
iframe.sandbox = "allow-scripts allow-same-origin";
// Optional, for demos that open new windows:
// iframe.sandbox += " allow-popups";The preview document served by the preview service includes a CSP header such as:
Content-Security-Policy: default-src 'none';
script-src 'sha256-' 'sha256-' https://cdn.codepen.io;
style-src 'sha256-' https://cdn.codepen.io;
img-src data: https:;
connect-src 'none';
frame-ancestors 'self' https://codepen.io;Inline scripts and styles are allowed only via hash whitelists generated at publish time. eval(), inline event handlers, and external script loads (except the CDN) are blocked.
Trust and Data Boundaries
Three distinct trust zones exist:
| Zone | Trust Assumption | Data Flow |
|---|---|---|
| Host page | Trusted by the end user; controls the embedding context. | Provides pen ID; receives no data back from the embed. |
| CodePen CDN / preview service | Trusted to serve static assets faithfully and apply correct CSP. | Serves HTML/CSS/JS to the iframe; logs embed requests for analytics. |
| Preview iframe | Trusted only to execute user code within sandbox constraints. | Receives static assets; cannot read host page data; cannot initiate network requests (connect-src 'none'). |
The sandbox attribute allow-same-origin is required so that the preview document can access its own origin's cookies/storage (if CodePen uses them for user-specific features), but the iframe's origin (cdpn.io) differs from the host page's origin, so the same-origin policy still blocks cross-origin access. The allow-scripts token permits JavaScript execution; without it, the iframe would be inert.
Operational Checks
Operations teams should verify the isolation guarantees on every deploy and periodically in production.
1. Iframe sandbox attribute verification
On a test page that includes a CodePen embed, open DevTools → Elements, locate the injected iframe, and confirm its sandbox attribute contains exactly:
allow-scripts allow-same-originIf allow-popups is present, confirm it is intentional (e.g., the pen uses window.open). Any additional tokens (allow-forms, allow-top-navigation, allow-modals) indicate a configuration drift.
2. CSP header inspection
In DevTools → Network, click the preview document request (the pen/{id} URL). Check the Content-Security-Policy response header. Verify:
script-srccontains only hash sources ('sha256-...') andhttps://cdn.codepen.io.connect-src 'none'is present (no outbound fetch/XHR/WebSocket).frame-ancestorsrestricts embedding to CodePen's own domains.
3. Parent access test
Inside the iframe's console (DevTools → Console, select the iframe's context from the dropdown), run:
try {
console.log(window.parent.location.href);
} catch (e) {
console.log('Blocked:', e.message);
}Expected result: a security error (e.g., "Blocked: Permission denied to access property 'location' on cross-origin object"). If the host URL logs, the sandbox is ineffective.
Failure Modes
Sandbox omitted or weakened
If the embed script is modified (by a compromised CDN, a malicious browser extension, or a site owner who self-hosts a modified copy) to drop the sandbox attribute, the iframe gains full same-origin privileges relative to its own origin (cdpn.io). It still cannot directly access the host page due to cross-origin policy, but it can:
- Read/write
cdpn.iocookies and storage. - Make authenticated requests to CodePen APIs.
- Navigate the top-level browsing context if
allow-top-navigationis added.
Mitigation: Subresource Integrity (SRI) on the embed script tag, and monitoring for unexpected script changes.
CSP misconfiguration on preview service
If the preview service omits script-src hashes or adds 'unsafe-inline', an attacker who can influence pen content (e.g., via a compromised CodePen account) could inject arbitrary script that runs in the cdpn.io origin. Combined with a missing sandbox, this escalates to host page compromise via postMessage or DOM clobbering.
Mitigation: Automated CSP linting in the preview service's CI pipeline; reject any response lacking hash-based script sources.
Preview service serves stale or tampered assets
If the CDN cache is poisoned or the preview service's asset resolution is hijacked, the iframe executes attacker-controlled code. The sandbox and CSP still limit blast radius to the cdpn.io origin, but user data stored on that origin (session tokens, saved pens) is at risk.
Mitigation: Immutable asset URLs (content-hashed), cache-control headers preventing stale serves, and signed asset manifests.
Design Change Triggers
The following feature requests would require re-evaluating the sandbox and CSP baseline:
| Proposed Change | Impact on Isolation | Required Adjustments |
|---|---|---|
| Server-side rendering (SSR) of pens | Preview service becomes stateful; may need access to user session. | Add allow-same-origin (already present); tighten CSP connect-src to allow only internal SSR endpoint; audit cookie scope. |
Custom domains for pens (e.g., demo.example.com) | Iframe origin matches host page origin → same-origin policy no longer isolates. | Remove allow-same-origin from sandbox; rely solely on allow-scripts; enforce strict CSP with nonce/hashes; consider Cross-Origin-Opener-Policy: same-origin. |
Allow external script URLs in pens (e.g., https://unpkg.com/react) | Expands script-src to third-party origins. | Require SRI hashes for every external script; add require-trusted-types-for 'script' to CSP; monitor third-party CDN security advisories. |
| Bidirectional communication (postMessage API) | Creates a data channel from iframe to host. | Define a strict message schema; validate origin on both sides; add allow-scripts only (no allow-same-origin); rate-limit messages. |
Each trigger moves the design away from the "smallest suitable" baseline. The default stance should be to reject changes that expand the attack surface unless a threat model review demonstrates mitigated risk.
Verification Checklist for Deployments
- Deploy embed script with SRI hash; verify browser loads it without integrity errors.
- Request a preview URL; confirm HTTP 200,
Content-Type: text/html, CSP header present and correct. - Load the preview URL directly in a browser; verify no console errors from CSP violations.
- Embed the pen on a test page (different origin); run the three operational checks above.
- Run automated regression: a headless browser script that injects the embed, reads the iframe's sandbox attribute, fetches the preview URL, parses CSP, and attempts parent access.
If any check fails, block the deployment and investigate the preview service or embed script build pipeline.
Limitations and Browser Support
The design assumes:
- Browser support for
iframe sandbox(all modern browsers; IE10+ with partial support). - CSP Level 2+ (hash sources,
frame-ancestors). - No legacy browser requirement (IE11, old mobile WebViews). If legacy support is mandatory, a fallback static image or code snippet must replace the live embed.
CodePen does not currently implement Cross-Origin-Embedder-Policy: require-corp or Cross-Origin-Opener-Policy: same-origin on the preview origin. Adding these would strengthen isolation against Spectre-class side-channel attacks but may break third-party resource loads.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.