# Bad value “X” for attribute “sandbox” on element “iframe”: Setting both “allow-scripts” and “allow-same-origin” is not recommended, because it effectively enables an embedded page to break out of all sandboxing.

> Canonical HTML version: https://rocketvalidator.com/html-validation/bad-value-x-for-attribute-sandbox-on-element-iframe-setting-both-allow-scripts-and-allow-same-origin-is-not-recommended-because-it-effectively-enables-an-embedded-page-to-break-out-of-all-sandboxing
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

The `sandbox` attribute is one of the most powerful security features available for `<iframe>` elements. When present with no value (or with specific tokens), it applies a strict set of restrictions to the embedded content — blocking scripts, form submissions, popups, same-origin access, and more. You selectively relax these restrictions by adding space-separated tokens like `allow-scripts`, `allow-forms`, or `allow-popups`.

The problem arises specifically when `allow-scripts` and `allow-same-origin` are used together. The `allow-scripts` token lets the embedded page execute JavaScript, while `allow-same-origin` lets it retain its original origin (rather than being treated as coming from a unique, opaque origin). With both enabled, the embedded page's JavaScript can access the parent page's DOM via `window.parent` (if they share the same origin) or, more critically, can use JavaScript to programmatically remove the `sandbox` attribute from its own `<iframe>` element. Once the attribute is removed, **all** sandboxing restrictions are lifted, making the `sandbox` attribute completely pointless.

This is why the W3C validator flags this combination — it's not technically invalid HTML, but it's a security anti-pattern that renders sandboxing ineffective. The WHATWG HTML specification explicitly warns against this combination for the same reason.

## How to fix it

The fix depends on what the embedded content actually needs:

1. **If the embedded page needs scripts but not same-origin access:** Remove `allow-same-origin`. The page can still run JavaScript but will be treated as a unique origin, preventing it from accessing cookies, storage, or the parent frame's DOM.

2. **If the embedded page needs same-origin access but not scripts:** Remove `allow-scripts`. The page retains its origin but cannot execute any JavaScript.

3. **If you believe both are required:** Reconsider whether sandboxing is the right approach. If the embedded content truly needs both script execution and same-origin access, the `sandbox` attribute provides no meaningful security benefit, and you may want to use other security mechanisms like `Content-Security-Policy` headers instead.

Always follow the principle of least privilege — only grant the permissions the embedded content strictly requires.

## Examples

### ❌ Bad: using both `allow-scripts` and `allow-same-origin`

```html
<iframe
  src="https://example.com/widget"
  sandbox="allow-scripts allow-same-origin">
</iframe>
```

This triggers the validator warning because the embedded page can use its script access combined with its preserved origin to break out of the sandbox entirely.

### ❌ Bad: both flags present alongside other tokens

```html
<iframe
  src="https://example.com/widget"
  sandbox="allow-forms allow-scripts allow-same-origin allow-popups">
</iframe>
```

Even with additional tokens, the presence of both `allow-scripts` and `allow-same-origin` still defeats the sandbox.

### ✅ Good: allowing scripts without same-origin access

```html
<iframe
  src="https://example.com/widget"
  sandbox="allow-scripts">
</iframe>
```

The embedded page can run JavaScript but is treated as a unique opaque origin, preventing it from accessing parent-page resources or removing its own sandbox.

### ✅ Good: allowing only the necessary permissions

```html
<iframe
  src="https://example.com/widget"
  sandbox="allow-scripts allow-forms allow-popups">
</iframe>
```

This grants script execution, form submission, and popup capabilities while keeping the content sandboxed in a unique origin.

### ✅ Good: using an empty sandbox for maximum restriction

```html
<iframe
  src="https://example.com/widget"
  sandbox="">
</iframe>
```

An empty `sandbox` attribute applies all restrictions — no scripts, no form submissions, no popups, no same-origin access, and more. This is the most secure option when the embedded content is purely static.

### ✅ Good: removing the sandbox when it provides no real benefit

```html
<iframe
  src="https://example.com/widget"
  title="Example widget">
</iframe>
```

If you genuinely need both script execution and same-origin access, it's more honest to omit `sandbox` entirely and rely on other security measures, rather than including an attribute that provides a false sense of security.
