iframe sandbox
sandbox is an <iframe> attribute that strips the framed document of
nearly every privilege, granting them back one token at a time. With a
bare sandbox, the document cannot run scripts, submit forms, open
popups, navigate the parent, or claim its own origin.
<iframe sandbox="allow-scripts" src="/report-body"></iframe>
The tokens worth knowing
| Token | Grants back |
|---|---|
allow-scripts |
JavaScript execution |
allow-same-origin |
The document's real origin — cookies, storage |
allow-forms |
Form submission |
allow-popups |
window.open |
allow-modals |
alert, confirm, prompt |
allow-downloads |
Downloads initiated by the frame |
allow-top-navigation |
Navigating the parent page |
The one combination to avoid
allow-scripts and allow-same-origin together defeat the sandbox.
With both, the framed document runs script in its real origin, which
means it can reach its own <iframe> element in the parent and remove
the sandbox attribute entirely. The HTML specification calls this out
directly. The pair is only acceptable when the content is already
trusted — at which point the sandbox was decoration.
For untrusted or generated HTML, allow-scripts alone is the line:
scripts run, the origin stays opaque.
Why report viewers need it
A generated HTML report is arbitrary HTML from whatever produced it. Serving it inline from an application's own origin would let it read the viewer's cookies and call the API as that user — which is exactly why chat apps and ticket trackers serve HTML attachments as downloads rather than rendering them (why Slack won't preview).
Sandboxing is the way to have both. Comma renders report bodies in an
iframe with allow-scripts and without allow-same-origin, so:
- Sorting, filtering, expanding failures, charts and drill-downs all work as they do locally.
- The report cannot touch cookies,
localStorageor the account around it. - The application's own CSP stays strict while the report keeps its own dependencies.
What the opaque origin costs
Very little, for reports. No cookies and no localStorage means a report
that persisted a filter selection between visits loses that. Anything
that fetches from its own origin at runtime needs its data uploaded with
it rather than fetched from elsewhere — which is the same requirement as
publishing the whole output directory in the first place.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.
Publish an interactive report →