Iframes are everywhere. You visit a website, and somewhere on the page there is an embedded video, a social media feed, an advertisement, or a third-party widget. All of those are iframes. They let you pull content from other sources into your page without having to host it yourself. That is convenient, but it also comes with risks.
The content inside an iframe runs in its own context, but it still has ways to interact with your page. It can run scripts, submit forms, redirect visitors, and in some cases, break out of the iframe and take over the whole page. If you are embedding content from a source you do not control, that source could be malicious or could become malicious later. You need ways to protect yourself and your visitors.
An iframe is like a window into another website. That website can do things. It can run JavaScript. It can show popups. It can try to trick users into clicking things. It can try to redirect the parent page. If the iframe content is from an untrusted source, you are effectively letting that source run code on your page.
This is not just theoretical. Malicious ads have used iframes to redirect users to scam sites. Compromised third-party widgets have been used to steal data from the pages they were embedded in. Even if you trust the source today, you do not know what it will do tomorrow. Their security might be worse than yours. They might get hacked. Their content might change.
On the other side of the equation, you might be the one whose content gets embedded in someone else's site. If you run a site that gets embedded in iframes, you need to control how and where your content appears. You do not want your site to be framed by malicious sites that try to trick users into thinking they are on your page when they are not.
The sandbox attribute is the most powerful tool for securing iframes. When you add sandbox to an iframe, you strip away almost all of its capabilities. The content inside cannot run scripts, cannot submit forms, cannot open popups, cannot navigate the parent page, cannot use plugins, and cannot access any of the usual browser features. It becomes isolated and relatively harmless.
But you usually want the iframe to do something. A video player needs to run scripts to play the video. A form needs to submit. So the sandbox attribute lets you add back the permissions you need, one by one. You start with everything blocked, then turn on only what is required.
Here is a basic sandboxed iframe with no permissions:
<iframe src="https://example.com" sandbox></iframe>
If you need to allow scripts, you add allow-scripts. If you need to allow form submission, you add allow-forms. If you need to allow the iframe to navigate the parent page, you add allow-top-navigation. Each permission is a specific token in the sandbox value.
Here is an iframe that can run scripts and submit forms but nothing else:
<iframe src="https://example.com" sandbox="allow-scripts allow-forms"></iframe>
The sandbox attribute has several tokens you can use. Allow-scripts lets the iframe run JavaScript. Without this, scripts inside the iframe do nothing. This is often needed for interactive content. But be careful. Scripts can still do malicious things. Only allow scripts if you trust the content.
Allow-same-origin allows the iframe to treat its content as coming from the same origin. Without this, the iframe is considered to be in a unique origin. This is a security feature. If you do not need the iframe to access cookies or local storage from its own domain, leave this out. It makes the iframe even more isolated.
Allow-forms lets the iframe submit forms. Allow-popups lets it open popup windows. Allow-modals lets it use alert, confirm, and other modal dialogs. Allow-top-navigation lets it change the URL of the parent page. This is dangerous. Only allow it if absolutely necessary.
Allow-pointer-lock lets the iframe capture mouse input. Allow-orientation-lock lets it lock screen orientation. There are more. Each one adds capabilities. The rule is simple: only add the ones you actually need. Start with an empty sandbox and add tokens until the iframe works. That gives you the minimum permissions required.
Now consider the other side. Someone might try to embed your site in an iframe on their page. If that page is malicious, they could use clickjacking to trick your users. Clickjacking is when an attacker puts your site in an iframe and overlays invisible elements on top. Users think they are clicking your buttons, but they are actually clicking on something the attacker controls.
To prevent this, you use the X-Frame-Options header or the frame-ancestors directive in CSP. X-Frame-Options is older and simpler. It tells browsers whether your site can be framed. You have three options. X-Frame-Options: DENY means no one can frame your site. X-Frame-Options: SAMEORIGIN means only pages from your own domain can frame your site. X-Frame-Options: ALLOW-FROM is the third option, but it has poor browser support and is not recommended.
The CSP frame-ancestors directive is the modern replacement. It gives you more control. You can specify exactly which domains can embed your site. For example:
Content-Security-Policy: frame-ancestors 'self' https://trustedpartner.com
This says only pages from your own domain and trustedpartner.com can embed your site. All other attempts get blocked. You can use 'none' to block all framing, just like DENY.
Most sites should set either DENY or SAMEORIGIN for X-Frame-Options, or the equivalent in CSP. Unless you have a specific reason to allow other sites to embed your content, block it. This stops clickjacking attacks cold.
When you embed content from another site, you have to balance functionality with security. Start with the most restrictive sandbox possible. Test what breaks. Add permissions one by one until it works. This takes a bit of work, but it is worth it.
For a YouTube video, you might need allow-scripts and allow-same-origin. YouTube uses JavaScript for controls and probably needs to access its own cookies for user preferences. You might also need allow-popups if the video has links that open in new windows. That is a reasonable set of permissions for embedded video.
For a Google Maps embed, you need allow-scripts for the interactive map controls. You might also need allow-same-origin for the map tiles. allow-popups if the map has links to more information. That is fine.
For an ad network, you have to trust the ad provider to not do anything malicious. You can still sandbox the iframe, but you have to give it the permissions it needs to work. Usually allow-scripts and allow-popups. There is no way around that. If you do not trust the provider, do not use their ads. If you do trust them, the sandbox still limits what they can do compared to an unsandboxed iframe.
One combination you need to be careful about is allow-same-origin and allow-scripts together. When both are present, the iframe can remove its own sandbox attribute through script. The sandbox is no longer enforced. The iframe can do anything.
This is a known behavior. If you give an iframe both permissions, you are effectively giving it the ability to escape the sandbox entirely. Only use this combination if you completely trust the content. For most third-party embeds, you do not have that level of trust. Avoid giving both permissions unless you have no other choice.
If you need both, consider whether you really need allow-same-origin. Often you can get away without it. The iframe might lose access to its own cookies and local storage, but that might be acceptable. If it breaks functionality, maybe the functionality is not essential.
Iframes involve two sides. You have the site that contains the iframe, and you have the site that provides the iframe content. Both sides need to think about security. If you are the container, you sandbox the iframe to protect your users from the embedded content. If you are the content provider, you use X-Frame-Options to control where your content appears.
These two protections work together. The container's sandbox limits what the iframe can do. The content provider's framing headers limit who can embed it. If a site tries to embed your content and you have DENY set, the browser blocks it regardless of what the container does. That is good. It gives you control over your own content.
If you run a site that gets embedded often, like a video platform or a mapping service, you probably want to allow framing. But you still want to control where your content appears. Use CSP frame-ancestors to list allowed domains. This way you can allow legitimate embeds while blocking malicious ones.
I have seen several cases where iframes caused security issues. One site embedded a third-party chat widget without any sandbox. The widget got compromised and started injecting ads into the parent page. The site owners had no idea until users started complaining. Adding a sandbox with allow-scripts and allow-same-origin would have contained the problem. The widget would still have run, but it could not mess with the parent page.
Another site allowed any user to embed any URL in an iframe. Attackers started embedding phishing pages that looked like the site's login page. Users thought they were still on the legitimate site. They entered their credentials. The phishing page captured them. The fix was to restrict allowed domains and sandbox all user-provided iframes.
A third site did not set X-Frame-Options. Attackers built a page that framed the site with an invisible overlay. Users thought they were clicking the legitimate buttons, but they were actually clicking on the attacker's overlay. This clickjacking attack tricked users into liking pages they did not intend to like. Adding X-Frame-Options: DENY stopped it.
Sometimes you do not need an iframe at all. Modern web APIs let you embed content in other ways. Web components and custom elements can encapsulate functionality without the overhead of an iframe. Fetch and JavaScript can load content dynamically and insert it into the page.
But iframes still have their place. They provide a strong isolation boundary. Content inside an iframe cannot access the parent DOM directly. It cannot read cookies from the parent. It cannot run scripts that affect the parent layout. If you are embedding untrusted content, that isolation is valuable. No other web feature gives you the same level of separation.
The key is to use iframes with the sandbox attribute. Do not just drop in an iframe and hope for the best. Take the time to configure it properly. It takes a few extra seconds to add sandbox and choose the right tokens. Those seconds save you from potential security headaches down the road.
After you set up iframes, test them. Open the browser developer tools. Look at the iframe in the elements panel. Check what permissions it has. Try to see if you can break out. If you have an iframe that should be sandboxed, verify that scripts inside it actually cannot run.
Test your framing headers as well. Try to embed your site in a test page. See if it loads. If you set DENY, it should not. If you set SAMEORIGIN, it should load only when the test page is on the same domain. This is easy to test and gives you confidence that your protections are working.
If you use CSP frame-ancestors, check that the header is being sent correctly. The browser developer tools show you the response headers. Make sure the CSP includes the frame-ancestors directive with the values you expect.
Iframes are not going away. They are too useful for embedding content from other sources. But you can use them safely. Make sandbox the default. Add permissions only when needed. Block framing of your own site unless you have a reason to allow it. These are simple practices that take little time but provide significant protection.
Every time you add an iframe to your site, ask yourself a few questions. Where does this content come from? Do I trust it? What permissions does it actually need? Could I get away with fewer permissions? The answers will guide you to a safer configuration.
Iframes can be a security risk, but they do not have to be. With the right protections, you can embed third-party content confidently, knowing that your visitors are safe and your site is secure.