Choose a sandboxed cross-origin iframe when the vendor allows it, because the widget cannot reach your DOM or cookies. Use a script tag only when the widget must interact deeply with your page, and then add CSP, version pinning and monitoring. OWASP recommends the iframe approach for vendor code.
The difference in one table
| Script tag | Cross-origin sandboxed iframe | |
|---|---|---|
| Runs in | Your page context | Its own origin and window |
| Can read your form fields | Yes | No |
| Can change your page | Yes | No, only its own frame |
| Communication | Direct function calls | postMessage, with origin checks |
| Layout integration | Full control | Fixed size or resize messages |
| Vendor support | Always | Not always offered |
| Page speed and styling | Shares your styles | Own styles, extra load |
OWASP's cheat sheet advises loading vendor code in a cross-origin iframe with a sandbox attribute so it cannot reach the host DOM or cookies, and exchanging messages through postMessage while checking the sender's origin.
Questions to decide
- Does the widget need to read or write your page? A chat bubble that only draws itself can live in a frame. A personalization script that rewrites your page cannot.
- Does it sit on a sensitive page? Login, checkout and account pages should carry as little third party code as possible.
- Does the vendor publish a frame based embed? Many payment and identity providers do, and it is often the supported route.
- Can you live with the layout limits? Frames need sizing and sometimes resize messages.
- What data would a compromised version reach? If the answer is credentials or payment details, push hard for the iframe.
How to set up the iframe safely
- Serve the widget from a different origin than your site.
- Add the sandbox attribute with the smallest token set that works. Start with none and add tokens as needed, see iframe sandbox tokens.
- Use postMessage with a specific target origin, never a wildcard, for anything sensitive.
- On receiving messages, check the origin and validate the data shape before acting.
- Add a frame-src directive in your CSP so only expected frame hosts load.
If you must use a script tag
- Pin an exact version and add an integrity hash if the file is static.
- Limit destinations with connect-src, see can a CSP stop a compromised script from sending data out.
- Keep it off pages with credentials where you can.
- Record an owner and review date in your script inventory.
Remember OWASP's warning that a data layer is not a sandbox. Anything running in your page's trust boundary stays inside it.
Safeguard scans the dependencies you bundle and builds an SBOM, which covers code you take into your own build rather than embedding. A free scan is at gold.safeguard.sh/scan.
Quick check
Is an iframe automatically safe?
No. It needs to be cross-origin, sandboxed with minimal tokens, and your message handling must check origins. A permissive sandbox gives little protection.
Why not iframe everything?
Some scripts must change your page to work, and frames add layout and performance work. Use frames where isolation is possible.
Sources
- OWASP, Third Party JavaScript Management Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html
Last reviewed: 19 October 2026.