DOMException: Blocked a frame with origin from accessing a cross-origin frame

avatar
Borislav Hadzhiev

Last updated: Apr 4, 2024
4 min

banner

# DOMException: Blocked a frame with origin from accessing a cross-origin frame

Depending on your browser, the error might be named differently:

  • Uncaught DOMException: Blocked a frame with origin from accessing a cross-origin frame.

  • Uncaught SecurityError: Blocked a frame with origin from accessing a frame with origin

The error "DOMException: Blocked a frame with origin from accessing a cross-origin frame" occurs when you load an <iframe> in HTML and try to access the elements within it using JavaScript.

You can't directly access an <iframe> with a different origin as that could lead to security vulnerabilities.

For example, if you could load an email service website in an iframe and access the HTML, then you could easily check if the user is logged in or not and retrieve potentially sensitive information.

This would make phishing attacks much easier than they currently are.

There are a couple of ways to get around this, e.g. using window.postMessage or disabling the same-origin policy in your browser.

The same-origin policy causes browsers to block scripts that are trying to access an iframe with a different origin.

For the origin to be considered different, at least one of the following 3 components has to be different:

  • protocol
  • hostname
  • port
shell
protocol://hostname:port/path

For example, suppose that the URL from which you are trying to access resources is the following:

  • https://www.example.com/articles

You would then be able to access the DOM in the following URLs using an iframe.

  • https://www.example.com/users
  • https://www.example.com/any/other/path
  • https://www.example.com
  • https://www.example.com:80 (Port 80 is the default)

However, you wouldn't be able to access the following URLs:

  • http://www.example.com/users - (Different protocol)
  • https://www.example.com:3000/users - (Different port)
  • https://subdomain.example.com/users - (Different hostname)
  • http://gmail.com/users?q=bobby+hadz- (Different protocol and hostname)

# Using the window.postMessage() method to get around this

If you own or have access to both pages, you can get around the same-origin policy by using the window.postMessage() method.

The method safely enables cross-origin communication between Window objects, e.g.:

  • between a page and a pop-up that it spawned
  • or between a page and an iframe that is embedded within it

For example, you could add the following code to your main page.

index.js
const frame = document.getElementById('YOUR-IFRAME-ID'); const data = { id: 1, name: 'bobby hadz', salary: 1500, }; frame.contentWindow.postMessage( // ๐Ÿ‘‡๏ธ data you want to pass to the other page data, 'https://YOUR-OTHER-PAGE.com', );

The first argument we passed to postMessage() is the data we want to send over to the other page.

The data variable doesn't have to be an object, it could be a simple string, an integer or any other value.

The second argument we passed to postMessage() can be a string containing an asterisk if you want to indicate that any origin can be the destination of the message.

index.js
frame.contentWindow.postMessage( // ๐Ÿ‘‡๏ธ data you want to pass to the other page data, // ๐Ÿ‘‡๏ธ no preference about the origin of the destination '*', );

However, it is usually better to be specific to avoid leaking data to other sites.

Then, in your <iframe> that is contained in the main page, your could would look similar to the following.

index.js
window.addEventListener('message', event => { // ๐Ÿ‘‡๏ธ check the origin of the data if (event.origin === 'https://YOUR-FIRST-PAGE.com') { // If this runs, the data was sent from your site // The data sent with postMessage() is accessed via // event.data console.log(event.data); } else { // If this runs, the data was NOT sent from your site // Make sure to not use this data // You can remove the `else` statement return; } });

The event.origin property enables you to check if the data was sent from your own site.

If the data was sent from your site, then you can access it using event.data.

If it wasn't sent from your site, then you shouldn't use it.

This approach can be used in both directions.

For example, you could also:

  1. Use the addEventListener() method on your main page.
  2. Receive the responses from the iframe.

# Disabling the same-origin policy to get around the error

You could also disable the same-origin policy to get around the error.

This stackoverflow page has instructions on how to disable the same-origin policy in Chrome.

As previously, the same-origin policy causes browsers to block scripts that are trying to access an iframe with a different origin.

For the origin to be considered different, at least one of the following 3 components has to be different:

  • protocol
  • hostname
  • port
shell
protocol://hostname:port/path

However, disabling the same-origin policy is not advisable and only affects your browser.

Note that running your browser with the same-origin policy setting disabled grants any website access to cross-origin resources which makes your browsing experience unsafe.

This should only be used for development purposes.

# Try to use a different browser and see if you still get the error

Another thing you can try is to use a different browser and see if you still get the error.

For example, if you get the error when using Chrome, try to use Firefox.

# If both pages run on the same domain, set document.domain

Something you can try if both pages run on the same domain but different ports (e.g. http://localhost:3000 and http://localhost:5000) is to set the document.domain property.

Each window has to set its domain to the shared origin (localhost in the example).

index.js
document.domain = 'localhost';

This should also work if the pages have different subdomains. For example:

  • https://abc.example.com
  • https://xyz.example.com

Then, each window has to set its domain as follows.

index.js
document.domain = 'example.com';

Most browsers ignore the hostname difference and enable you to treat the pages as if they came from the same origin.

index.js
const frame = document.getElementById('YOUR-IFRAME-ID'); frame.contentWindow.document.body.classList.add('my-class');

If this doesn't work in Chrome, try using a different browser, e.g. Firefox.

However, note that the property has been deprecated.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev