After adding sandbox to a third-party <iframe>, its form stops submitting, its "open in new tab" links do nothing, and its export button downloads nothing. Which sandbox tokens restore each behaviour, and what happens to a popup the frame does open?
answer
- one symptom, one token
- the failures are silent, check the console
- the new window is born sandboxed too
- escaping is a separate, wider grant
- hosting location decides the same-origin question
basics
~10 sAdd allow-forms for submission, allow-popups for new-tab links and window.open, and allow-downloads for the export. A popup opened from a sandboxed frame inherits the frame's sandbox flags unless you also grant allow-popups-to-escape-sandbox.
solid answer
~40 sEach broken behaviour maps to exactly one token: `allow-forms` restores form submission, `allow-popups` makes `window.open` and `target="_blank"` work instead of silently doing nothing, and `allow-downloads` lets the frame initiate a file download. So the element becomes `sandbox="allow-scripts allow-forms allow-popups allow-downloads"` — `allow-scripts` being needed for the widget's own code. The detail interviewers probe is inheritance: a window opened from a sandboxed frame is itself sandboxed with the same flags, so a popup that must run as a normal page needs `allow-popups-to-escape-sandbox` as well — a token that visibly widens the blast radius and should be justified, not assumed. The method matters more than the list: add one token per observed failure, verify, and stop. Resist the reflex of granting `allow-same-origin` because something still misbehaves.
go deeper
Learn the direct mappings: allow-forms for form submission, allow-popups for new windows, allow-downloads for file downloads, allow-scripts for the frame's own code. Know these failures happen silently.
Explain that sandbox failures produce no thrown error in the frame's own logic — window.open just returns null — and that a popup opened from a sandboxed frame inherits the frame's flags unless allow-popups-to-escape-sandbox is granted.
Show the method: reproduce, read the console message, add exactly one token, verify, stop. Justify the wide grants explicitly and treat the final token list as a documented contract with the third party rather than whatever made the demo work.
Own the embed policy across the product: a default token set every vendor embed starts from, an exception path with a named owner for wide grants like popups-to-escape-sandbox or top navigation, and a review trigger for when a vendor changes their embed code.
## The debugging method A sandboxed embed fails **silently**. Forms do not submit and no error is thrown; `window.open` returns `null`; a download simply never starts. The browser's console usually does log a sandbox-related message, and that message names the missing token — reading it is faster than guessing. The discipline is: reproduce one broken behaviour, identify the single token that governs it, add that token, re-test. Never add three at once, and never respond to unexplained breakage by granting the most powerful token you can think of. ## Mapping symptoms to tokens - **A form inside the frame does not submit** → `allow-forms`. Note this covers submission specifically; typing into the fields was never blocked, which is why the failure looks like a broken button. - **`target="_blank"` links and `window.open` do nothing** → `allow-popups`. Without it `window.open` returns `null`, so widget code that does `const w = window.open(...); w.location = ...` throws a `TypeError` on the second line, which is often the first visible symptom. - **An export or "download PDF" button produces no file** → `allow-downloads`. Downloads are blocked in a sandboxed frame regardless of whether the frame's script ran. - **`alert`, `confirm`, `prompt` or `window.print()` are ignored** → `allow-modals`. - **The widget wants to send the whole tab somewhere** → `allow-top-navigation-by-user-activation` in preference to `allow-top-navigation`, so it can only happen off a real user gesture. - **The widget's own script does not run at all** → `allow-scripts`, which for any interactive third-party embed is table stakes. ## Popup inheritance — the part people miss Adding `allow-popups` gets the window to open, but that new window is **created with the opener frame's sandbox flags**. So the popup is itself sandboxed: no scripts if the frame had none, no forms if the frame had none, and an opaque origin. For an OAuth-style flow or a payment window this is usually fatal — the popup needs to be a normal document. That is what `allow-popups-to-escape-sandbox` is for: it says popups opened from this frame are created *without* the sandbox flags. It is a deliberately wide grant, because a frame you have contained can now open an uncontained window. Grant it only when you know why the popup needs it, and prefer restructuring — for instance, having your own page open the window rather than the embed — where that is possible. ## The finished element ```html <iframe src="https://widget.example/checkout" sandbox="allow-scripts allow-forms allow-popups allow-downloads" allow="payment 'src'" referrerpolicy="strict-origin" loading="lazy" title="Checkout widget"></iframe> ``` Read as four independent decisions: which baseline capabilities the document keeps (`sandbox`), which powerful feature is delegated (`allow`), how much referrer information its requests carry (`referrerpolicy`), and when it is fetched (`loading`). The `title` is not optional in practice — assistive technology announces frames by that string, and without it the user hears only that a frame exists. ## The token you should hesitate over Nothing in this symptom list is fixed by `allow-same-origin`. If someone reaches for it, the real question is what the widget is trying to do — usually read its own cookies or storage. That is a legitimate need for a genuinely third-party embed served from its own origin: `allow-same-origin` restores *the vendor's* origin, not yours, and the frame still cannot touch your page. It is only self-defeating when the framed content is served from your own origin, where combining it with `allow-scripts` puts the frame back inside your trust boundary. So the answer to "can I add it?" is a question about where the content is hosted, not about which symptom you are chasing. ## What to say when the vendor asks for everything A common real-world ending is the vendor's integration guide saying "do not sandbox our embed". Treat that as a negotiation, not a verdict: start from the token set that makes their demo work, hand them the list, and ask which specific token each of their remaining requirements needs. Most vendor guidance predates anyone asking. The token set you end up with is a documented contract about what that third party can do inside your page — which is exactly the artefact an interviewer wants to hear you produce.
- Why does a widget's window.open call throw a TypeError under sandbox rather than just failing?Because `window.open` returns `null` when popups are blocked by the sandbox, and typical widget code immediately dereferences the result — `w.location = url` or `w.focus()` — which throws on `null`. The underlying cause is still the missing `allow-popups` token; the TypeError is downstream noise that sends people debugging the wrong file.
- An embedded widget opens an OAuth popup that must run scripts and set cookies. What do you grant?`allow-popups` alone is not enough — the popup inherits the frame's flags and would be sandboxed too. It needs `allow-popups-to-escape-sandbox` so the new window is created without sandbox flags. That is a wide grant, so the better move where you control the integration is to have your own page open the OAuth window and pass the result back to the frame.
- How would you decide whether allow-top-navigation is ever acceptable for a third-party embed?Almost never in its unconditional form — it lets a vendor's frame redirect the user's whole tab at any moment, which is the classic malicious-ad behaviour. If the embed has a genuine "continue in the main window" flow, grant `allow-top-navigation-by-user-activation` instead, which permits it only as the direct result of a user gesture.
saying these in an interview costs you the question
- Adds every allow-* token at once to make the embed work
- Assumes a popup from a sandboxed frame is an ordinary window
- Grants allow-same-origin to fix an unrelated symptom
- Thinks a blocked form submission raises a visible error
- Grants allow-top-navigation when the user-activation variant would do