🚀AdvancedSecurity

Advanced iframe: Sandbox & Security

Master the sandbox attribute, allow attribute, and security considerations for embedding third-party content safely in iframes.

Overview

The `<iframe>` element is powerful but carries significant security risk when embedding untrusted third-party content. The `sandbox` attribute restricts what an embedded frame can do blocking scripts, form submission, top-level navigation, and more unless you explicitly re-enable each capability. By default, `sandbox` applies all restrictions simultaneously. You then add back only the capabilities the embedded content actually needs: `allow-scripts` to run JavaScript, `allow-forms` to submit forms, `allow-same-origin` to access cookies and storage. The key rule: never combine `allow-same-origin` and `allow-scripts` on the same iframe this combination allows the embedded page to remove its own sandbox entirely. Modern iframes also use the `allow` attribute (Permissions Policy), `referrerpolicy`, `loading`, and `csp` attribute for fine-grained control.

Key Points

  • •`sandbox` with no value applies all restrictions; add capabilities individually
  • •`allow-scripts` enables JS execution in the frame
  • •`allow-same-origin` lets the frame access its origin's cookies/storage (NEVER combine with allow-scripts)
  • •`allow-forms` enables form submission; `allow-popups` enables window.open()
  • •`allow-top-navigation` lets the frame navigate the parent window (dangerous in ads)
  • •`srcdoc` attribute embed inline HTML directly without a URL (runs in about:blank, no same-origin access)
  • •`referrerpolicy="no-referrer"` prevents the Referer header from leaking your URL to embedded content

Examples

Secure embedding of third-party content

<!-- Embed a user-provided HTML snippet safely -->
<!-- srcdoc is treated as same-origin to about:blank no access to your site -->
<iframe
  srcdoc="<h1>User Content</h1><p>Hello World</p>"
  sandbox="allow-scripts"
  width="600"
  height="300"
  title="User content preview"
></iframe>

<!-- Embed a payment widget with minimal permissions -->
<iframe
  src="https://payment.provider.com/widget"
  sandbox="allow-scripts allow-forms allow-same-origin allow-popups"
  allow="payment"
  referrerpolicy="no-referrer-when-downgrade"
  width="400"
  height="200"
  title="Payment form"
></iframe>

<!-- Embed an advertisement with strict sandbox -->
<iframe
  src="https://ads.network.com/banner"
  sandbox="allow-scripts allow-popups"
  allow="autoplay 'none'"
  referrerpolicy="no-referrer"
  loading="lazy"
  title="Advertisement"
></iframe>

For ads: no allow-same-origin (can't access your cookies), no allow-top-navigation (can't hijack your page).

The sandbox allow-same-origin + allow-scripts security hole

<!--
  ⚠️ CRITICAL SECURITY WARNING ⚠️

  NEVER do this with content you don't fully trust:
-->

<!--
  When combined, the embedded page can:
  1. Run JS (allow-scripts)
  2. Treat itself as same-origin to your site (allow-same-origin)
  3. Therefore: modify its own sandbox attribute and REMOVE IT ENTIRELY
  4. Then run unrestricted same-origin JS on your site

  Example attack: sandbox="allow-scripts allow-same-origin"
  -> embedded JS does: frameElement.removeAttribute('sandbox');
  -> Now it can read your localStorage, make requests as the user, etc.
-->

<!-- ✅ CORRECT patterns: -->

<!-- Only scripts, no same-origin access (for CDN widgets) -->
<iframe src="..." sandbox="allow-scripts"></iframe>

<!-- Only same-origin (for trusted sub-apps, no additional JS needed) -->
<iframe src="/app-module" sandbox="allow-same-origin allow-forms"></iframe>

This combination is one of the most dangerous HTML security mistakes.

postMessage communication between parent and iframe

<!-- parent.html -->
<iframe id="child" src="/child.html" sandbox="allow-scripts"></iframe>

<script>
const frame = document.getElementById('child');

// Send message to iframe
frame.contentWindow.postMessage(
  { type: 'INIT', data: { userId: 42 } },
  'https://yoursite.com'  // target origin specify exactly, never use '*' with sensitive data
);

// Receive message from iframe
window.addEventListener('message', (event) => {
  // ALWAYS verify origin before processing
  if (event.origin !== 'https://yoursite.com') return;
  console.log('Received from iframe:', event.data);
});
</script>

<!-- child.html (inside the iframe) -->
<script>
// Receive message from parent
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://yoursite.com') return;
  console.log('Parent says:', event.data);

  // Reply to parent
  window.parent.postMessage({ type: 'READY' }, event.origin);
});
</script>

Always verify event.origin in message handlers never use "*" for sensitive communication.

Common Mistakes

  • Combining sandbox="allow-scripts allow-same-origin" on untrusted content the iframe can remove its own sandbox
  • Using postMessage with targetOrigin="*" for sensitive data any page can receive the message
  • Not adding sandbox at all to embedded ads or third-party widgets they can navigate your page, steal focus, or access your cookies

Note

The `csp` attribute on iframes (still experimental in some browsers) lets you impose a Content Security Policy on the embedded frame: `<iframe csp="script-src 'none'">` this adds another layer of protection on top of sandbox.

Exercises

Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What does adding the sandbox attribute to an iframe WITHOUT any values do?