iFrame sandbox permissions tutorial

Jim rottinger.

Software Engineer at Looker

Understanding iFrame sandboxes and iFrame security

Embedding third-party JavaScript in web applications is a tale as old as time. Whether it’s dropping a widget onto your web page or including custom content from a client in your cloud application, it’s something that many developers have encountered in their career. We all know about the iframe element in HTML, but how much do we really know about how it works? What are the security concerns associated with running code inside of an iframe and, furthermore, how can the HTML5 sandbox attribute on the frame alleviate these concerns?

The goal of this tutorial is to walk through the various security risks associated with running third-party JavaScript on your page and explain how sandboxed iframes can alleviate those issues by restricting the permissions it is allowed to run with.

In this post, we’ll demonstrate setting up a demo application from the ground up that will simulate running JavaScript coming from a different origin. What we should end up with is a sandboxed environment in which we can execute any arbitrary JavaScript and still sleep well at night, knowing our host application will be safe from harm.

With all of that in mind, the guided walkthrough will consist of the following parts:

  • Setting up two node servers to simulate two different origins
  • Embedding the content of our client page in an iframe on the host page and investigating what the client iframe is and is not allowed to do
  • Applying the sandbox attribute to the iframe and exploring the various options for the sandbox.

Let’s get started!

Step 1: Setting up the servers for our demo application

To simulate executing code from a different origin, we are going to set up two node servers — one which we’ll call the host and second which we will call the client. We can do this using node’s http library to listen to and serve from two different ports.

Save this JS file to whatever name you’d like - I called it server.js. Then, to start our server, we can simply run:

This should start two different http servers, one on port 8000 and the second on port 8001. To test that it is working, you can individually visit your localhost on port 8000 and 80001, which should look like this:


Even though they are both running on localhost, the  same-origin policy  that browsers implement operate on a protocol-host-port tuple that will only be true if the protocol, the hostname, and port number all match up. In this case, the protocol and host are the same, but since the ports are different, these will be considered to be different origins.

Of course, just having a hard-coded response won’t get us very far. We’ll need to be able to serve both HTML and JS for this demo. To do this, I whipped up a function to serve assets from a given folder.

This function will take in a root folder path, a url, and the response object. If the file is not found, it will return 404. If it is found, it will set the header to be text/javascript or text/html, depending on the file suffix. To get this to work, we need to include two more dependencies at the top of the file:

Fun fact - Since we’re just using built-in node libraries, we do not have to install anything via npm! Once you instantiate fileSystem, path, and our asset function, go ahead and update your servers as well to call serveAsset.

These now look very similar. The only difference is that the host_server will look for its assets in the host folder and the client_server will look in the client folder. If we were to restart our server now, we would see the following error message:


This is because our serveAsset function is looking in either the host or client folder for an asset to serve, and we haven’t created them yet! Let’s create both of them, each with an index.html and a JS file.

Our file structure should look like this:

Now, if we start our server and visit our localhost location, we no longer get the 404, which means our server found the file! — but it has no content yet. To get some content in, let’s start with something very simple. For the host, we simply have the HTML as:

And the JavaScript as:

The client content is exactly the same, just with the word host changed to client. If we restart our server now, we should be able to go to both http://localhost:8000/ and http://localhost:8001/ and see our content in action! Each page should send an alert from the JS file and then render our html content to the page.


Each node server is serving an index.html file which includes a JavaScript file

Step 2: Embedding the client in the host without sandboxing and investigating its permissions

With our two servers running, we are now ready to begin testing some iframe scenarios. Before we do that, let’s add a second file to our host so that we can compare the permissions of an iframe from the same origin and an iframe from a different origin.

Fill in the content of these files with the same content as we used for our other html/JS pairs. We’ll call this one the “Hosted Client,” meaning an iframe client coming from the same origin as our host.

Once we do that, back in our host/index.html we can iframe both our same-origin client and our different-origin client.

Please note that we use localhost for the hosted-client and for the other. This will become important in the cookies section below. Refreshing the host page, you should now see two iframes, each with the content of our individual HTML files.

If you have alerts in your JS files like I do, you should have seen that each individual file triggers an alert at the top level of the browser. Should it be able to do this? That question brings us to our first area of concern — pop-ups and dialog boxes.

Pop-ups and dialog boxes

JavaScript has three different functions that trigger a popup — alert, prompt, and confirm. Each of these open up a dialog box at the top of the browsing context, regardless of whether it comes from the top-level window or not. The scary thing about these dialogs, as can be found in the  alert documentation , is:

“Dialog boxes are modal windows — they prevent the user from accessing the rest of the program’s interface until the dialog box is closed. For this reason, you should not overuse any function that creates a dialog box (or modal window).”

I am sure that most of us have, at some point in our lives, been forcefully redirected to a spammy site against your will that then bombarded you with these types of dialogs. Even when you try to close out of it, it just pops open another one. This annoying behavior completely blocks you out of using a site and sadly, it’s incredibly simple to reproduce. Try adding this to your client.js file:

Now, when you visit your host site, you get this:

These prompts make it impossible to ever interact with the page and you have to close the entire tab or kill the JavaScript execution to get rid of it. The worst part is that regardless of whether your embedded content is coming from a different host or the same origin, this behavior is exploitable.

You might think that you could just do something like this to get rid of it:

The problem with this is that each iframe operates within its own nested browsing context, so overriding the functions at the host level will not affect the functions at the frame level.

Fortunately, sandboxing can come to our rescue here, which we will see later in this post. For now, let’s move on to whether or not the iframe can navigate the page away from the current one.

Step 3: Top-level window navigation and opening new tabs

Let's now examine how and if the iframes are able to change the url of the top-level window and if they’re able to open a new window.

There are two different methods that we want to test here.

  • window.open for opening new windows and tabs, and
  • window.location for navigating the page away from the current url.

Helpful note: iframes can reference its top-level window using window.top. Similarly, it can reference its parent’s window with window.parent. In our case, they do the same thing.

Let’s remove all the code in client.js and replace it with:

This will attempt to redirect the top-level window to the client host. If we run this, we get the following error:


That’s great! It blocks the automatic redirect. But wait — what’s that last part? “… nor has it received a user gesture.”

What does that mean? Does it mean that a user-initiated gesture can navigate the window? Let’s try it.

If we add this code to our JS and HTML respectively, it will add a link to the client page. When we click it, the page navigates!

As it turns out, a user-initiated action can navigate the top-level window, which is the basic idea behind clickjacking. A typical  clickjacking  attack will put transparent click boxes over a page and then “hijack” the click to redirect the page to a different url. window.open works the same way.

If we have this, the browser will block the pop-up request of the outer function call, however, when we have it in a click handler, it will open the window regardless of whether we blocked pop-ups or not.

The other part of the above error message saying the iframe “does not have the same origin as the window it is targeting” means our iframe is the same origin as the host and it has full access to redirect the page, click-action or not.

If you run this, the browser will allow the redirect to happen since it is the same origin. This is not the case for window.open. Even if it is from the same origin, the browser will block the window.open unless you explicitly tell the browser to allow the pop-up.

Cookies and browser requests

The final thing we are going to look at is browser cookies. Before getting started, make sure your hosted-client iframe is pointed at localhost and your client.js iframe is pointed at

We need to do this because cookies care about domain and ignore the port. Once you have checked this, let’s set a cookie on the host.

This is representing a session ID, something that is often included in requests. Let’s see if our iframes can access the cookies.

As you can see, the client cannot access the cookies since it is a different origin, but the hosted-client can. Let’s try to make a request using the fetch API.

When we do this, we get a 200 response.

That means the server accepted the request and gave us a response, but did it send through the cookies? We can check this on the server side. Let’s add a console log to our host server request handler.

This will output the headers when we make a request to our host server. Make sure you restart the server after you add this line, and then reload your page and look for the request coming from the hosted-client. It looks like this:

As you can see, it sends the cookies through. If the server were to use just the session ID to authenticate the request, then it would think this is a legitimate request.

Step 4: Applying the sandbox attribute to the iFrame

So far, we’ve identified four areas of concern when working with iframes.

  • They can exploit pop-up dialog boxes to prevent interaction with the website
  • Navigating the top-level window through clickjacking even on different-origin iframes
  • Navigating the top-level window when the origin is the same even without user interaction
  • Same-origin iframes can make requests with cookies.

Now we’re going to begin making use of the sandbox attribute for iframes, introduced in HTML5. When added to an iframe, the sandboxed iframe restricts pretty much all scripts and browser behavior of any kind. It is not until we add the permissions in a space-separated list that we enable the exact permissions we want to set. To see its initial state, add the attribute as an empty string to both of our iframes.

When we sandbox the iframe, it blocks all scripts from executing


Sandboxed iframes with no permissions block all scripts from running

Getting this to work starts by allowing various permissions one at a time . The full list of string values can be found in the iframe documentation under the sandbox section. We will be starting with allow-scripts.

Allowing scripts

To begin here, let’s clear out our client.js and hosted-client.js and start with a simple console log.

Without defining any permissions, our sandbox won’t allow a console log to run. We can get our script running by adding the allow-scripts permission to our iframe attribute.

Once you do this, and refresh the page, you should see a console log from each of our pages.

Pop-ups and modals

One of the concerns we learned about is that an iframe can pop up dialog boxes at the top of the browsing context and prevent the user from interacting with the page. To see if this is exploitable in a sandbox, let’s add an alert to our client script.

When we run that we get the following error:

Even though we are allowing scripts to run, the sandbox still limits a lot of the browser behaviors. In order for the alert to work from the iframe, we would have to add the allow-modals property to the iframe.

Keep in mind that this is an all-or-nothing thing. We cannot allow some popups and block others. This is an okay restriction, in my opinion, and it crosses off our first iframe security concern.

Top-level window navigation and opening new tabs

Our second and third security concerns are related to navigating the page away from the original URL. We saw that a same-origin iframe could navigate the page without a user interaction, and that a different-origin iframe could do so with user interaction. Let’s try this in our sandbox.

This results in the following errors:


With this, we covered two cases at once. The initial command to change the location failed, as did the one on-click. By applying separate permissions to our iframe for each of these cases, we can allow any navigation with allow-top-navigation and user-activated navigation with allow-top-navigation-by-user-activation.

When we turn this on, the different-origin iframe can redirect the page upon user action. The case is the same for same-origin iframes, where you can explicitly set the navigation permissions, regardless of the origin.

The final concern to address is the ability to access cookies and make requests with same-origin iframes. Let’s try accessing the cookies with a sandboxed iframe.

Unlike last time, this results in the following error:

Similarly, when we try to make a request with the same request code as the previous section, we get a different error.

The above error is the browser blocking our request because we no longer have the same origin. This is because the sandbox property sets the origin of the frame to null, meaning it will now be a cross-origin request, even though the iframe is hosted on the same domain.

Adding the allow-same-origin sandbox attribute will prevent both of these errors from occurring. However, you should be careful and make sure you have complete control over the content of the frame before using it. As noted in the  Mozilla iframe documentation :

“When the embedded document has the same origin as the main page, it is strongly discouraged to use both allow-scripts and allow-same-origin at the same time, as that allows the embedded document to programmatically remove the sandbox attribute. Although it is accepted, this case is no more secure than not using the sandbox attribute.”

Generally speaking, if you find yourself needing both allow-scripts and allow-same-origin for your sandbox, you should ask yourself why you are iframing in the first place, and whether or not having the sandbox property is appropriate.

Putting it all together: how we use iFrames at Looker

As an example of a practical use of this, here at Looker, we use iframes to allow customers to create and run their own custom visualizations within our application.

Without any one way to vet every single line of code our customers could write for their custom visualizations, we needed to create a secure execution environment to run the code in. A diagram of this environment can be seen below.


Looker explore page using an iframe to render custom data visualization

We leverage the postMessage API to pass the data in and to receive back any events or errors that the visualization produces. Given the restrictions of the sandboxed iframe, it is not able to make calls outside of its own frame, nor is it able to read or modify anything about the parent page. This let’s us rest assured that both our application and our customers’ data is safe and secure.

Wrapping up

I hope you found this post helpful as you address security concerns related to sandboxed iframes. By walking through this tutorial, you should now have a better understanding of:

  • How sandboxed iframes without allow-modals permission prevent user interaction on the page
  • How sandboxed iframes without the allow-top-navigation or the allow-top-navigation-by-user-activation properties can alleviate same-origin iframes that can redirect the top-level page, as well as different-origin iframes with some user interaction.
  • Why sandboxed iframes without the allow-same-origin property prevent same-origin iframes from having access to the domain’s cookies and making requests as if they were the host.

If you have any questions about this tutorial, feel free to reach out on the  Looker Community . And if you’re curious to learn more about our Looker team, check out our  open positions .

Important notes

  • Although sandboxing is very powerful for security, don’t put all of your security eggs in the sandbox basket, as it is  not supported by IE9 and below .
  • If you struggled with any part of this tutorial, all of the code can be found in the  sandbox-sandbox repository .
  • Data Analytics
  • Google Cloud

Related articles


From data chaos to data clarity: How Tamr's Data Products leverage Google generative AI

By Dr. Ali Arsanjani • 11-minute read

Achieve higher performance and lower query cost for BigQuery integer or timestamp lookups

By Jing Mao • 6-minute read


UPS leverages BigQuery and Striim for AI-secured package delivery

By Pinaki Mitra • 5-minute read

More flexibility for your Dataflow jobs with new controls for latency versus cost

By Yi Ding • 4-minute read

  • Español – América Latina
  • Português – Brasil
  • Tiếng Việt

Play safely in sandboxed IFrames

Mike West X Homepage

Constructing a rich experience on today's web almost unavoidably involves embedding components and content over which you have no real control. Third-party widgets can drive engagement and play a critical role in the overall user experience, and user-generated content is sometimes even more important than a site's native content. Abstaining from either isn't really an option, but both increase the risk that Something Bad™ could happen on your site. Each widget that you embed -- every ad, every social media widget -- is a potential attack vector for those with malicious intent:

Content Security Policy (CSP) can mitigate the risks associated with both of these types of content by giving you the ability to whitelist specifically trusted sources of script and other content. This is a major step in the right direction, but it's worth noting that the protection that most CSP directives offer is binary: the resource is allowed, or it isn't. There are times when it would be useful to say "I'm not sure I actually trust this source of content, but it's soooo pretty! Embed it please, Browser, but don't let it break my site."

Least Privilege

In essence, we're looking for a mechanism that will allow us to grant content we embed only the minimum level of capability necessary to do its job. If a widget doesn't need to pop up a new window, taking away access to window.open can't hurt. If it doesn't require Flash, turning off plugin support shouldn't be a problem. We're as secure as we can be if we follow the principle of least privilege , and block each and every feature that isn't directly relevant to functionality we'd like to use. The result is that we no longer have to blindly trust that some piece of embedded content won't take advantage of privileges it shouldn't be using. It simply won't have access to the functionality in the first place.

iframe elements are the first step toward a good framework for such a solution. Loading some untrusted component in an iframe provides a measure of separation between your application and the content you'd like to load. The framed content won't have access to your page's DOM, or data you've stored locally, nor will it be able to draw to arbitrary positions on the page; it's limited in scope to the frame's outline. The separation isn't truly robust, however. The contained page still has a number of options for annoying or malicious behavior: autoplaying video, plugins, and popups are the tip of the iceberg.

The sandbox attribute of the iframe element gives us just what we need to tighten the restrictions on framed content. We can instruct the browser to load a specific frame's content in a low-privilege environment, allowing only the subset of capabilities necessary to do whatever work needs doing.

Twust, but verify

Twitter's "Tweet" button is a great example of functionality that can be more safely embedded on your site via a sandbox. Twitter allows you to embed the button via an iframe with the following code:

To figure out what we can lock down, let's carefully examine what capabilities the button requires. The HTML that's loaded into the frame executes a bit of JavaScript from Twitter's servers, and generates a popup populated with a tweeting interface when clicked. That interface needs access to Twitter's cookies in order to tie the tweet to the correct account, and needs the ability to submit the tweeting form. That's pretty much it; the frame doesn't need to load any plugins, it doesn't need to navigate the top-level window, or any of a number of other bits of functionality. Since it doesn't need those privileges, let's remove them by sandboxing the frame's content.

Sandboxing works on the basis of a whitelist. We begin by removing all permissions possible, and then turn individual capabilities back on by adding specific flags to the sandbox's configuration. For the Twitter widget, we've decided to enable JavaScript, popups, form submission, and twitter.com's cookies. We can do so by adding a sandbox attribute to the iframe with the following value:

That's it. We've given the frame all the capabilities it requires, and the browser will helpfully deny it access to any of the privileges that we didn't explicitly grant it via the sandbox attribute's value.

Granular Control over Capabilities

We saw a few of the possible sandboxing flags in the example above, let's now dig through the inner workings of the attribute in a little more detail.

Given an iframe with an empty sandbox attribute, the framed document will be fully sandboxed, subjecting it to the following restrictions:

  • JavaScript will not execute in the framed document. This not only includes JavaScript explicitly loaded via script tags, but also inline event handlers and javascript: URLs. This also means that content contained in noscript tags will be displayed, exactly as though the user had disabled script herself.
  • The framed document is loaded into a unique origin, which means that all same-origin checks will fail; unique origins match no other origins ever, not even themselves. Among other impacts, this means that the document has no access to data stored in any origin's cookies or any other storage mechanisms (DOM storage, Indexed DB, etc.).
  • The framed document cannot create new windows or dialogs (via window.open or target="_blank" , for instance).
  • Forms cannot be submitted.
  • Plugins will not load.
  • The framed document can only navigate itself, not its top-level parent. Setting window.top.location will throw an exception, and clicking on link with target="_top" will have no effect.
  • Features that trigger automatically (autofocused form elements, autoplaying videos, etc.) are blocked.
  • Pointer lock cannot be obtained.
  • The seamless attribute is ignored on iframes the framed document contains.

This is nicely draconian, and a document loaded into a fully sandboxed iframe poses very little risk indeed. Of course, it also can't do much of value: you might be able to get away with a full sandbox for some static content, but most of the time you'll want to loosen things up a bit.

With the exception of plugins, each of these restrictions can be lifted by adding a flag to the sandbox attribute's value. Sandboxed documents can never run plugins, as plugins are unsandboxed native code, but everything else is fair game:

  • allow-forms allows form submission.
  • allow-popups allows (shock!) popups.
  • allow-pointer-lock allows (surprise!) pointer lock.
  • allow-same-origin allows the document to maintain its origin; pages loaded from https://example.com/ will retain access to that origin's data.
  • allow-scripts allows JavaScript execution, and also allows features to trigger automatically (as they'd be trivial to implement via JavaScript).
  • allow-top-navigation allows the document to break out of the frame by navigating the top-level window.

With these in mind, we can evaluate exactly why we ended up with the specific set of sandboxing flags in the Twitter example above:

  • allow-scripts is required, as the page loaded into the frame runs some JavaScript to deal with user interaction.
  • allow-popups is required, as the button pops up a tweeting form in a new window.
  • allow-forms is required, as the tweeting form should be submittable.
  • allow-same-origin is necessary, as twitter.com's cookies would otherwise be inaccessible, and the user couldn't log in to post the form.

One important thing to note is that the sandboxing flags applied to a frame also apply to any windows or frames created in the sandbox. This means that we have to add allow-forms to the frame's sandbox, even though the form only exists in the window that the frame pops up.

With the sandbox attribute in place, the widget gets only the permissions it requires, and capabilities like plugins, top navigation, and pointer lock remain blocked. We've reduced the risk of embedding the widget, with no ill-effects. It's a win for everyone concerned.

Privilege Separation

Sandboxing third-party content in order to run their untrusted code in a low-privilege environment is fairly obviously beneficial. But what about your own code? You trust yourself, right? So why worry about sandboxing?

I'd turn that question around: if your code doesn't need plugins, why give it access to plugins? At best, it's a privilege you never use, at worst it's a potential vector for attackers to get a foot in the door. Everyone's code has bugs, and practically every application is vulnerable to exploitation in one way or another. Sandboxing your own code means that even if an attacker successfully subverts your application, they won't be given full access to the application's origin; they'll only be able to do things the application could do. Still bad, but not as bad as it could be.

You can reduce the risk even further by breaking your application up into logical pieces and sandboxing each piece with the minimal privilege possible. This technique is very common in native code: Chrome, for example, breaks itself into a high-privilege browser process that has access to the local hard-drive and can make network connections, and many low-privilege renderer processes that do the heavy lifting of parsing untrusted content. Renderers don't need to touch the disk, the browser takes care of giving them all the information they need to render a page. Even if a clever hacker finds a way to corrupt a renderer, she hasn't gotten very far, as the renderer can't do much of interest on its own: all high-privilege access must be routed through the browser's process. Attackers will need to find several holes in different pieces of the system order to do any damage, which hugely reduces the risk of successful pwnage.

Safely sandboxing eval()

With sandboxing and the postMessage API , the success of this model is fairly straightforward to apply to the web. Pieces of your application can live in sandboxed iframe s, and the parent document can broker communication between them by posting messages and listening for responses. This sort of structure ensures that exploits in any one piece of the app do the minimum damage possible. It also has the advantage of forcing you to create clear integration points, so you know exactly where you need to be careful about validating input and output. Let's walk through a toy example, just to see how that might work.

Evalbox is an exciting application that takes a string, and evaluates it as JavaScript. Wow, right? Just what you've been waiting for all these long years. It's a fairly dangerous application, of course, as allowing arbitrary JavaScript to execute means that any and all data an origin has to offer is up for grabs. We'll mitigate the risk of Bad Things™ happening by ensuring that the code is executed inside of a sandbox, which makes it quite a bit safer. We'll work our way through the code from the inside out, starting with the frame's contents:

Inside the frame, we have a minimal document that simply listens for messages from its parent by hooking into the message event of the window object. Whenever the parent executes postMessage on the iframe's contents, this event will trigger, giving us access to the string our parent would like us to execute.

In the handler, we grab the source attribute of the event, which is the parent window. We'll use this to send the result of our hard work back up once we're done. Then we'll do the heavy lifting, by passing the data we've been given into eval() . This call has been wrapped up in a try block, as banned operations inside a sandboxed iframe will frequently generate DOM exceptions; we'll catch those and report a friendly error message instead. Finally, we post the result back to the parent window. This is pretty straightforward stuff.

The parent is similarly uncomplicated. We'll create a tiny UI with a textarea for code, and a button for execution, and we'll pull in frame.html via a sandboxed iframe , allowing only script execution:

Now we'll wire things up for execution. First, we'll listen for responses from the iframe and alert() them to our users. Presumably a real application would do something less annoying:

Next, we'll hook up an event handler to clicks on the button . When the user clicks, we'll grab the current contents of the textarea , and pass them into the frame for execution:

Easy, right? We've created a very simple evaluation API, and we can be sure that code that's evaluated doesn't have access to sensitive information like cookies or DOM storage. Likewise, evaluated code can't load plugins, pop up new windows, or any of a number of other annoying or malicious activities.

You can do the same for your own code by breaking monolithic applications into single-purpose components. Each can be wrapped in a simple messaging API, just like what we've written above. The high-privilege parent window can act as a controller and dispatcher, sending messages into specific modules that each have the fewest privileges possible to do their jobs, listening for results, and ensuring that each module is well-fed with only the information it requires.

Note, however, that you need to be very careful when dealing with framed content that comes from the same origin as the parent. If a page on https://example.com/ frames another page on the same origin with a sandbox that includes both the allow-same-origin and allow-scripts flags, then the framed page can reach up into the parent, and remove the sandbox attribute entirely.

Play in your sandbox

Sandboxing is available for you now in a variety of browsers: Firefox 17+, IE10+, and Chrome at the time of writing ( caniuse, of course, has an up-to-date support table ). Applying the sandbox attribute to iframes you include allows you to grant certain privileges to the content they display, only those privileges which are necessary for the content to function correctly. This gives you the opportunity to reduce the risk associated with the inclusion of third-party content, above and beyond what is already possible with Content Security Policy .

Moreover, sandboxing is a powerful technique for reducing the risk that a clever attacker will be able to exploit holes in your own code. By separating a monolithic application into a set of sandboxed services, each responsible for a small chunk of self-contained functionality, attackers will be forced to not only compromise specific frames' content, but also their controller. That's a much more difficult task, especially since the controller can be greatly reduced in scope. You can spend your security-related effort auditing that code if you ask the browser for help with the rest.

That's not to say that sandboxing is a complete solution to the problem of security on the internet. It offers defense in depth, and unless you have control over your users' clients, you can't yet rely on browser support for all your users (if you do control your users clients -- an enterprise environment, for example -- hooray!). Someday… but for now sandboxing is another layer of protection to strengthen your defenses, it's not a complete defense upon which you can soley rely. Still, layers are excellent. I suggest making use of this one.

Further Reading

" Privilege Separation in HTML5 Applications " is an interesting paper that works through the design of a small framework, and its application to three existing HTML5 apps.

Sandboxing can be even more flexible when combined with two other new iframe attributes: srcdoc , and seamless . The former allows you to populate a frame with content without the overhead of an HTTP request, and the latter allows style to flow into the framed content. Both have fairly miserable browser support at the moment (Chrome and WebKit nightlies). but will be an interesting combination in the future. You could, for example, sandbox comments on an article via the following code:

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License , and code samples are licensed under the Apache 2.0 License . For details, see the Google Developers Site Policies . Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2013-01-04 UTC.

Escaping Improperly Sandboxed Iframes

2020-05-06 | security.

Thanks to iframe's sandbox attribute, it is possible to specify restrictions applied on content displayed inside the iframe. The documentation strongly discourages from using both allow-scripts and allow-same-origin values due to security risks it may introduce. In this blogpost, I am going to explain and demonstrate why.

In Mozilla's developer documentation on <iframe> , you can find the following remark related to allow-scripts and allow-same-origin values of the sandbox attribute:

When the embedded document has the same origin as the embedding page, it is strongly discouraged to use both allow-scripts and allow-same-origin , as that lets the embedded document remove the sandbox attribute — making it no more secure than not using the sandbox attribute at all.

When I first read this note, I thought that escaping will be fairly straightforward:

  • Accessing window.parent from the page inside the iframe,
  • getting the iframe element reference via Document Object Model (DOM) functions, such as .getElementById() or .getElementsByTagName() ,
  • removing the iframe's sandbox element via .removeAttribute("sandbox") ,
  • calling alert() function to create a modal window despite allow-modals was not set for the iframe, hence escaping from the iframe's restrictions.

Unfortunatelly, this rather naïve approach does not work. From my experiments, the reason for that is the fact that browsers apply restrictions on the <iframe> 's content when loading the page . When I subsequently change or remove the sandbox attribute and then call "illegal" functions, browser will still block them.

On the following lines I will demonstrate the simplest solution I have been able to come up with. Before I get to it, let me explain the terminology I am using - a child page refers to a page that is being displayed in the iframe , while a parent page refers to a page that contains the <iframe> element.

Let's have a look at parent page, in index.html :

This is the page that we need to modify from the child page ( kid.htm ). To escape the iframe as I outlined above, I will be popping an alert() from the child page inside the parent.

One of the simplest solutions I have been able to come up with is to simply create a new iframe in place of the old one, and let the child page know it has been loaded in unrestricted mode. I will walk you through the process step by step.

First, I will obtain a reference to the parent window and verify the iframe in question still exists. If the original iframe is missing , it means that the child page is loaded from another iframe - the one we are going to create in step 2 as a replacement:

In the second step, I expand the body of the condition to create unrestricted iframe and to remove the original one with restrictions:

Now, when the parent page loads the child page into the iframe with allow-scripts and allow-same-origin , the child page manages to escape the original iframe's restrictions and execute its code.

Both of the files I used in this demonstration are available on my Github . You can also try for yourself on my Github Pages .

Can you think of a simpler way to escape? Please let me know!

HTML References

Html <iframe> sandbox attribute.

❮ HTML <iframe> tag

An <iframe> with extra restrictions:

More "Try it Yourself" examples below.

Definition and Usage

The sandbox attribute enables an extra set of restrictions for the content in the iframe.

When the sandbox attribute is present, and it will:

  • treat the content as being from a unique origin
  • block form submission
  • block script execution
  • disable APIs
  • prevent links from targeting other browsing contexts
  • prevent content from using plugins (through <embed> , <object> , <applet> , or other)
  • prevent the content to navigate its top-level browsing context
  • block automatically triggered features (such as automatically playing a video or automatically focusing a form control)

The value of the sandbox attribute can either be empty (then all restrictions are applied), or a space-separated list of pre-defined values that will REMOVE the particular restrictions.

Browser Support

The numbers in the table specify the first browser version that fully supports the attribute.


Attribute Values

More examples.

An <iframe> sandbox allowing form submission:

An <iframe> sandbox allowing scripts:

Get Certified



Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail: [email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail: [email protected]

Top Tutorials

Top references, top examples, get certified.

  • | New Account
  • | Log In Remember [x]
  • | Forgot Password Login: [x]
  • Format For Printing
  •  -  XML
  •  -  Clone This Bug
  •  -  Top of page

Facebook One Box Error

Facebook One Box Error on Latest 2.7.0.beta1 version.

ErrorUtils caught an error: Failed to set the ‘domain’ property on ‘Document’: Assignment is forbidden for sandboxed iframes. [Caught in: Module “lowerDomain”] Subsequent non-fatal errors won’t be logged; see https://fburl.com/debugjs .

Same error show when I do F12 on following post.

Can you provide an example?


This error is coming from Facebook API because we are loading the video in a sandbox iframe for security reasons.

As I can see here the video works fine even with the error from Facebook so it’s not blocking the feature? The alternate here would be to not onebox the video at all which seems even worse.

This topic was automatically closed after 39 hours. New replies are no longer allowed.

Related Topics

Can the FB API be used in Codepen?

Evening all, My random quote generator is still a work in progress, but I wanted to see if this was possible at all. I added a FB post button here , which will first prompt you to log in to facebook, and then post the quote to your wall. However, when running this via Codepen, I receive an error such as this:

After doing some googling, it doesn’t look like it’d be possible and I have been able to post on my own local host so it shouldn’t be the code itself. Is there a way from Codepen (or other sandboxed iframes) that this would be possible?

From what I understand from a quick couple of minutes (very quick so I might be explaining it wrong) of reading is codepen doesn’t allow iframes and this Facebook API creates an iframe for the share window. This will work in a site not hosted/created in codepen. So what you can do is fake this action by creating a new pop up window to mimic the iframe with the facebook share page. I created a small codpen to show you how.


Navigation Menu

Search code, repositories, users, issues, pull requests..., provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications You must be signed in to change notification settings

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to not set sandbox attribute on iframe for testing with cypress #2434


migg24 commented Dec 16, 2021


hardl commented Dec 16, 2021

  • 👍 1 reaction

Sorry, something went wrong.


migg24 commented Dec 29, 2021


No branches or pull requests


记一次iframe 跨域问题的解决

assignment is forbidden for sandboxed iframes

  问题背景是这样的,我需要调试一个html页面在我的android壳上运行,这个html放在了assets目录下,页面里嵌套了一个iframe标签,iframe标签对应的子页面里面有一些js方法需要调用,在Hbuilder上运行后确定没有问题,于是就拿android真机调试。结果已经知道了,调不通。      关于这个问题的解决方案,网上有好多,但大多数我试了都不行。一种是,将html放到服务器上,这个我没去尝试,但是估摸着可以,由于我需要是在assets目录下的,这样解决的话有点治标不治本。第二种,说是设置domain,因为我这个属于主域相同,子域不同,说可以这么干,然而试了一下后,不行,会报这样的错: Failed to set the ‘domain’ property on ‘Document’: ‘xxx’ is not a suffix of ”.” 最后,终于找到了可行的方法,加上下面这行代码:    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){   webView.getSettings().setAllowUniversalAccessFromFileURLs(true); }

  至此,问题终于解决,不过学无止境,坑也永远没有填满的时候,所以我去搜了这个setAllowUniversalAccessFromFileURLs,结果看到了这篇,感觉以后会有用,先记下。 Hybrid App经验解读

  总结:android webview真是坑中之王,需要一定的积累才能从容得应对这个坑王啊。

assignment is forbidden for sandboxed iframes


assignment is forbidden for sandboxed iframes


assignment is forbidden for sandboxed iframes

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

assignment is forbidden for sandboxed iframes

问 如何在沙盒iframe上允许document.domain? EN




Stack Overflow用户

发布于 2020-11-06 00:41:00





Copyright © 2013 - 2024 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有 

深圳市腾讯计算机系统有限公司 ICP备案/许可证号: 粤B2-20090059  深公网安备号 44030502008569

腾讯云计算(北京)有限责任公司 京ICP证150476号 |   京ICP备11018762号 | 京公网安备号11010802020287


  1. Iframes and Sandboxed Iframes

    assignment is forbidden for sandboxed iframes

  2. Uncaught DOMException: Failed to set the 'domain' property on 'Document

    assignment is forbidden for sandboxed iframes

  3. What's the point of forbidding a sandboxed iframe with allow-scripts

    assignment is forbidden for sandboxed iframes

  4. iFrame sandbox permissions tutorial

    assignment is forbidden for sandboxed iframes

  5. Uncaught DOMException: Failed to set the 'domain' property on 'Document

    assignment is forbidden for sandboxed iframes

  6. Is it possible to send a postMessage to a sandboxed iframe WITHOUT the

    assignment is forbidden for sandboxed iframes


  1. Counter IFRAMES Uses

  2. iframe in html

  3. sniper sandboxed

  4. How to Add iFrames to Duda Websites

  5. part-7 HTML series

  6. Sandboxie ถาวร,เปิดได้หลายจอ


  1. How can I allow document.domain on a sandboxed iframe?

    1. Note that since you are willing to set this document.domain to allow access between the two contexts, the sandbox is completely useless: The iframe could remove its own sandbox attributes. So as has been said in the previous comment, don't set the sandbox at all if it's really the way you want to go. But in your position, I would reconsider ...

  2. iFrame sandbox permissions tutorial

    When added to an iframe, the sandboxed iframe restricts pretty much all scripts and browser behavior of any kind. It is not until we add the permissions in a space-separated list that we enable the exact permissions we want to set. To see its initial state, add the attribute as an empty string to both of our iframes.

  3. Play safely in sandboxed IFrames

    Play safely in sandboxed IFrames. Constructing a rich experience on today's web almost unavoidably involves embedding components and content over which you have no real control. Third-party widgets can drive engagement and play a critical role in the overall user experience, and user-generated content is sometimes even more important than a ...

  4. Escaping Improperly Sandboxed Iframes

    Escaping Improperly Sandboxed Iframes. Thanks to iframe's sandbox attribute, it is possible to specify restrictions applied on content displayed inside the iframe. The documentation strongly discourages from using both allow-scripts and allow-same-origin values due to security risks it may introduce. In this blogpost, I am going to explain and ...

  5. HTML iframe sandbox Attribute

    Definition and Usage. The sandbox attribute enables an extra set of restrictions for the content in the iframe.. When the sandbox attribute is present, and it will:. treat the content as being from a unique origin; block form submission; block script execution; disable APIs; prevent links from targeting other browsing contexts

  6. Use the Twitch JSON API

    I found a solutions to fix the second error: Assignment is forbidden for sandboxed iframes. Ones the iframe element rendered have to add an attribute to the iframe: document.getElementsByTagName("iframe")[0].setAttribute("sandbox", "allow-scripts allow-top-navigation"); Now if click on twitchTV icon it's open the channel in new tab…

  7. web browser

    Update: I'd like to clarify the question a bit, based on the questions raised by commenters. There are many reasons to include third-party scripts in a page - advertisement, analytics, interaction with social networks, etc. This is a security concern though, in fact it's one of the reasons people use AdBlock or NoScript (so you can seletively choose which domains are allowed to run code in ...

  8. Uncaught DOMException: Failed to set the 'domain' property on ...

    Uncaught DOMException: Failed to set the 'domain' property on 'Document': Assignment is forbidden for Sandboxed iFrames

  9. Issues with linking to Twitch from CodePen IFrame #1340

    Yep, it still is. I get this EM: Uncaught SecurityError: Failed to set the 'domain' property on 'Document': Assignment is forbidden for sandboxed iframes. I am able to create the links in my own codepen so I don't worry about it too much. Thanks for trying and greets, Karin Meersman(Mientje) Date: Tue, 10 Nov 2015 22:29:35 -0800

  10. 175281

    The SandboxingFlag enumeration is missing an option for "Document.Domain" access. We should add this so that websites can block frames from manipulating the frame's domain.

  11. Facebook One Box Error

    This topic was automatically closed after 39 hours. New replies are no longer allowed.

  12. Can the FB API be used in Codepen?

    Uncaught DOMException: Failed to set the 'domain' property on 'Document': Assignment is forbidden for sandboxed iframes. After doing some googling, it doesn't look like it'd be possible and I have been able to post on my own local host so it shouldn't be the code itself.

  13. iFrame Sandbox Permissions Tutorial

    When added to an iframe, the sandboxed iframe restricts pretty much all scripts and browser behavior of any kind. It is not until we add the permissions in a space-separated list that we enable ...

  14. Add option to not set sandbox attribute on iframe for testing with

    We are running a luigi application and an app inside it in an iframe created by luigi. Luigi framework automatically adds sandbox attribute with some default allow settings and as a user I could add some more. But what I cannot do is remove the sandbox completely.

  15. 记一次iframe 跨域问题的解决

    文章浏览阅读1.1w次,点赞4次,收藏7次。记一次iframe 跨域问题的解决这几天,本来想轻轻松松的干会活,没想到遇上了拦路虎,愁了好几天,今天终于在Stack Overflow上找到答案。 问题背景是这样的,我需要调试一个html页面在我的android壳上运行,这个html放在了assets目录下,页面里嵌套了一个iframe ...

  16. 问 如何在沙盒iframe上允许document.domain?

    我有一个沙盒iframe,定义如下: 当我设置 在iframe内部,我得到以下错误: Uncaught DOMException: Failed to set the 'domain' property on 'Document': Assignment is forbidden for sandboxed ifra...

  17. iframe

    Sandbox access violation: Blocked a frame at "My url" from accessing a frame at "null". The frame being accessed is sandboxed and lacks the "allow-same-origin" flag. This is how an iframe is formed:

  18. failed to set the 'domain' property on 'document' assignment is

    注册. failed to set the 'domain' property on 'document' assignment is forbidden for sandboxed iframes. 您遇到的错误是因为您正在尝试在沙盒 iframe 中设置 document.domain 属性。. 这是不允许的,因为它会破坏 iframe 的隔离性,并可能导致安全漏洞。. 为了解决这个问题,您可以使用 ...

  19. javascript

    Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question.Provide details and share your research! But avoid …. Asking for help, clarification, or responding to other answers.