Security Headers

Cross-Origin Isolation Guide

Understand how COEP, COOP, and CORP work together to create strong security boundaries between your site and other origins, protecting against Spectre-class attacks and unlocking powerful browser APIs.

SiteSecurityScore Team·10 min read·Updated Feb 20, 2026

What is Cross-Origin Isolation? #

Two web pages are "cross-origin" when they differ in protocol, domain, or port. For example, https://your-site.com and https://other-site.com are cross-origin because their domains are different. Even http://your-site.com and https://your-site.com are cross-origin because the protocol differs.

Cross-origin isolation is a browser security state that completely separates your page from content loaded from other origins. When a page is cross-origin isolated, the browser guarantees that no cross-origin resource can leak data into your page's process, and your page cannot accidentally access data from other origins. This separation is enforced at the operating system process level, not just through JavaScript restrictions.

This concept became critical after the discovery of Spectre and Meltdown in 2018. These hardware vulnerabilities showed that a malicious script could use high-precision timers and shared memory to read data from other origins that happened to share the same process. In response, browsers disabled features like SharedArrayBuffer (a tool for sharing memory between JavaScript threads) on pages that were not cross-origin isolated. To re-enable these features, you need to prove that your page is safe by setting the right combination of security headers.

  • Prevents Spectre-class side-channel attacks from reading cross-origin data
  • Re-enables SharedArrayBuffer for high-performance applications
  • Provides access to high-resolution timers like performance.measureUserAgentSpecificMemory()
  • Creates strong process-level boundaries between your site and other origins

The Three Headers #

Cross-origin isolation requires three headers working together. Each one controls a different aspect of how your page interacts with other origins. Think of them as three locks on the same door: all three must be engaged for the security guarantee to hold.

Cross-Origin-Embedder-Policy (COEP)

COEP controls which cross-origin resources your page is allowed to load. When set to require-corp, every cross-origin resource your page loads must explicitly grant permission through a CORP header or CORS (Cross-Origin Resource Sharing, a mechanism that lets servers specify who can access their resources). If a resource does not grant permission, the browser blocks it.

COEP header
Cross-Origin-Embedder-Policy: require-corp

Values: require-corp (strict, requires all resources to opt in), credentialless (sends requests without credentials, less strict), unsafe-none (default, no restrictions). Learn more in the COEP reference article.

Cross-Origin-Opener-Policy (COOP)

COOP controls how your page can be referenced by windows or tabs opened from other origins. When set to same-origin, your page is placed in its own browsing context group. This means that a cross-origin page that opened your page (or was opened by your page) cannot access your window object, and you cannot access theirs.

COOP header
Cross-Origin-Opener-Policy: same-origin

Values: same-origin (strongest isolation), same-origin-allow-popups (allows popups to retain their opener), unsafe-none (default). Learn more in the COOP reference article.

Cross-Origin-Resource-Policy (CORP)

CORP controls who is allowed to load your resources. It is the counterpart to COEP: while COEP says "I will only load resources that grant me permission," CORP is how resources grant that permission. When a resource sets Cross-Origin-Resource-Policy: cross-origin, it is telling any page "you are allowed to load me." When set to same-origin, only pages from the same origin can load the resource.

CORP header
Cross-Origin-Resource-Policy: same-origin

Values: same-origin (only your origin), same-site (same registered domain), cross-origin (any origin). Learn more in the CORP reference article.

Enabling Cross-Origin Isolation #

To achieve cross-origin isolation, your page needs to send both COOP and COEP headers. Once both are set correctly, the browser puts your page into a cross-origin isolated state. Here is the step-by-step process.

1Audit Your Cross-Origin Resources

Before setting COEP, identify every cross-origin resource your page loads: images from CDNs, fonts from Google Fonts, analytics scripts, embedded iframes, and third-party widgets. Each of these needs to either include a CORP header or be served with proper CORS headers, or it will be blocked once you enable COEP.

2Set CORP on Your Own Resources

For resources that only your site needs (your own images, scripts, stylesheets), set Cross-Origin-Resource-Policy: same-origin. For resources you want to share with other sites (such as a public API), set it to cross-origin.

3Add CORS to Third-Party Resources

For third-party resources where you cannot control the CORP header, add the crossorigin attribute to the HTML element that loads them. This tells the browser to make a CORS request, and if the server includes an Access-Control-Allow-Origin header in its response, the resource will load successfully.

4Set COOP and COEP on Your Page

Once all your resources are prepared, set both headers on your HTML document response:

Required headers
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp

5Verify Isolation

Open your browser's Developer Tools console and check:

Verify isolation status
// Returns true if cross-origin isolation is active console.log(self.crossOriginIsolated); // true

Common Challenges #

Enabling cross-origin isolation can be challenging when your site loads resources from multiple third-party services. Here are the most common issues and how to work around them.

Third-Party Resources Without CORS or CORP

Many CDN-hosted images, fonts, and scripts do not include CORP headers and do not support CORS. When you enable COEP with require-corp, these resources will be blocked. You have several options:

  • Use credentialless instead of require-corp for COEP. This sends requests without cookies or credentials, and many servers will respond with the correct CORS headers.
  • Host critical third-party resources on your own domain so they become same-origin.
  • Contact the third-party provider and request that they add CORP or CORS headers.

Analytics and Tracking Scripts

Analytics scripts from providers like Google Analytics typically need credentials (cookies) to function correctly. Using credentialless may cause them to lose tracking context. Test your analytics carefully after enabling cross-origin isolation. Some providers have updated their scripts to work with cross-origin isolated pages, so check their documentation for guidance.

Payment and Authentication Popups

If your site uses OAuth login flows or payment providers that open popup windows, setting COOP to same-origin will break the communication between the popup and your page. In this case, use same-origin-allow-popups instead, which allows your page to retain a reference to popups it opens while still isolating windows opened by other origins.

Tip

Start by enabling COEP with credentialless rather than require-corp. This is less strict and works with more third-party resources while still providing meaningful isolation. You can tighten it to require-corp later once all your resources are properly configured.

Implementation Guide #

Below are complete configurations for implementing all three cross-origin isolation headers on common web servers and frameworks.

Apache

httpd.conf or .htaccess
# Add to httpd.conf or .htaccess # Enable cross-origin isolation Header always set Cross-Origin-Embedder-Policy "require-corp" Header always set Cross-Origin-Opener-Policy "same-origin" # Protect your own resources from being loaded by other origins Header always set Cross-Origin-Resource-Policy "same-origin" # For resources you intentionally share (e.g., a public API): # Header always set Cross-Origin-Resource-Policy "cross-origin"

Nginx

nginx.conf or site configuration
# Add to nginx.conf or site configuration # Enable cross-origin isolation add_header Cross-Origin-Embedder-Policy "require-corp" always; add_header Cross-Origin-Opener-Policy "same-origin" always; # Protect your own resources add_header Cross-Origin-Resource-Policy "same-origin" always; # For a public assets location that others should be able to load: # location /public-assets/ { # add_header Cross-Origin-Resource-Policy "cross-origin" always; # }

Node.js / Express

Express middleware
const express = require('express'); const app = express(); // Enable cross-origin isolation app.use((req, res, next) => { res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); res.setHeader('Cross-Origin-Resource-Policy', 'same-origin'); next(); }); // Or use Helmet with cross-origin isolation options: const helmet = require('helmet'); app.use(helmet({ crossOriginEmbedderPolicy: { policy: 'require-corp' }, crossOriginOpenerPolicy: { policy: 'same-origin' }, crossOriginResourcePolicy: { policy: 'same-origin' } }));

HTML: Loading Cross-Origin Resources

When loading resources from other origins on a page with COEP enabled, add the crossorigin attribute to tell the browser to make a CORS request:

HTML crossorigin attribute
<!-- Images from a CDN that supports CORS --> <img src="https://cdn.example.com/image.png" crossorigin /> <!-- Fonts from Google Fonts --> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter" crossorigin /> <!-- Scripts from a CORS-enabled CDN --> <script src="https://cdn.example.com/lib.js" crossorigin></script>

Testing and Verification #

After implementing the headers, verify that cross-origin isolation is working correctly using these methods.

JavaScript Runtime Check

The most direct way to verify isolation is through JavaScript. Open your browser console and check the crossOriginIsolated property:

Runtime isolation check
// Check if the page is cross-origin isolated if (self.crossOriginIsolated) { console.log('Cross-origin isolation is active'); // SharedArrayBuffer and other restricted APIs are available } else { console.log('Cross-origin isolation is NOT active'); // Check headers and resource loading for issues }

Chrome DevTools

In Chrome DevTools, the Network tab shows which resources were blocked by COEP. Look for resources with a status of "(blocked:NotSameOriginAfterDefaultedToSameOriginByCoep)" in the network log. The Console tab will also show warnings about resources that were blocked due to missing CORP or CORS headers.

Command Line Verification

curl header check
# Check all three cross-origin headers at once curl -sI https://your-site.com | grep -i "cross-origin" # Expected output: # Cross-Origin-Embedder-Policy: require-corp # Cross-Origin-Opener-Policy: same-origin # Cross-Origin-Resource-Policy: same-origin

Automated Scanning

Use SiteSecurityScore to scan your site for all three cross-origin headers. The scanner reports whether each header is present, shows its current value, and provides specific recommendations if any are missing or misconfigured.

For more background on cross-origin isolation, see the web.dev cross-origin isolation guide and MDN SharedArrayBuffer documentation.

Was this helpful?
Share

Test Your Cross-Origin Headers

Scan your website to check whether COEP, COOP, and CORP are properly configured and get specific implementation recommendations.