Cross-Origin Embedder Policy (COEP)

HTTP security header that controls how documents can embed cross-origin resources to prevent security vulnerabilities.

What is Cross-Origin Embedder Policy (COEP)?

Cross-Origin Embedder Policy (COEP) is an HTTP security header that controls how documents can embed cross-origin resources such as images, scripts, stylesheets, and iframes. COEP works in conjunction with Cross-Origin Opener Policy (COOP) to provide a secure environment for web applications by preventing unauthorized cross-origin resource loading.

COEP ensures that all cross-origin resources loaded by a document have explicitly opted into being embedded, which helps prevent spectre-style attacks and other cross-origin security vulnerabilities.

Header Syntax

The COEP header uses the following syntax:

Cross-Origin-Embedder-Policy: <value>

Where <value> can be one of:

  • unsafe-none: No policy (default behavior)
  • require-corp: Requires all cross-origin resources to explicitly opt-in to being embedded

How COEP Works

When a document sets COEP to require-corp, the browser enforces that:

  1. All cross-origin resources must include either:
    • Cross-Origin-Resource-Policy header
    • CORP header
    • Or be served with CORS headers that allow the embedding
  2. Resources without proper opt-in headers are blocked
  3. The document is isolated from other browsing contexts

Security Benefits

Prevents unauthorized resource loading:

  • Stops malicious sites from embedding sensitive resources
  • Prevents data exfiltration through embedded content
  • Blocks unauthorized tracking through embedded resources

Enables process isolation:

  • Allows browsers to use separate processes for different origins
  • Reduces the impact of potential vulnerabilities
  • Improves overall browser security

Mitigates Spectre-style attacks:

  • Prevents cross-origin data leakage
  • Reduces attack surface for side-channel vulnerabilities
  • Enhances memory isolation between origins

COEP Values Explained

unsafe-none (Default)

  • No restrictions on embedding cross-origin resources
  • Vulnerable to various security attacks
  • Not recommended for security-sensitive applications

require-corp

  • All cross-origin resources must explicitly opt-in to being embedded
  • Provides maximum security
  • Enables advanced isolation features
  • May break existing applications that don't support CORP

Implementation Requirements

For COEP to work effectively, both the embedding document and the embedded resources must cooperate:

  1. Embedding document must set:
    Cross-Origin-Embedder-Policy: require-corp
    Cross-Origin-Opener-Policy: same-origin
    
  2. Embedded resources must set one of:
    Cross-Origin-Resource-Policy: same-origin
    Cross-Origin-Resource-Policy: same-site
    Cross-Origin-Resource-Policy: cross-origin
    

    Or use CORS headers:
    Access-Control-Allow-Origin: https://embedding-site.com
    

Example Scenarios

Vulnerable scenario (no COEP):

<!-- Any site can embed this image without permission -->
<img src="https://bank.com/sensitive-image.jpg" alt="Sensitive data">

Protected scenario (with COEP):

// Bank website sets COEP header
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

// Image resource sets CORP header
Cross-Origin-Resource-Policy: same-origin

Embedding with CORS:

<!-- Image allows embedding via CORS -->
<img src="https://api.example.com/image.jpg" crossorigin="anonymous">

Implementation Examples

HTTP Response Header:

Cross-Origin-Embedder-Policy: require-corp

Web Server Configuration Examples:

Apache (.htaccess):

Header set Cross-Origin-Embedder-Policy "require-corp"
Header set Cross-Origin-Opener-Policy "same-origin"

Nginx:

add_header Cross-Origin-Embedder-Policy "require-corp";
add_header Cross-Origin-Opener-Policy "same-origin";

Express.js (Node.js):

app.use((req, res, next) => {
  res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
  res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
  next();
});

Best Practices

  1. Start with require-corp for security-sensitive applications
  2. Combine with COOP for maximum isolation
  3. Ensure all embedded resources support CORP or CORS
  4. Test thoroughly as COEP can break existing functionality
  5. Use Subresource Integrity (SRI) for additional security:
    <script src="https://example.com/library.js"
            integrity="sha384-..."
            crossorigin="anonymous"></script>
    
  6. Combine with other security headers:

Common Use Cases

  1. Online banking platforms: Protect sensitive financial data
  2. Healthcare applications: Secure patient information
  3. Government websites: Protect classified or sensitive data
  4. Enterprise applications: Secure internal company data
  5. Social media platforms: Prevent unauthorized data access
  6. E-commerce sites: Protect customer payment information

Browser Support

COEP is supported in modern browsers:

  • Chrome 83+
  • Firefox 97+
  • Edge 83+
  • Safari 16.4+

Debugging COEP Issues

Common COEP-related issues and solutions:

  1. Resources failing to load:
    • Check if resources have proper CORP or CORS headers
    • Verify the embedding document has correct COEP/COOP headers
  2. Iframes not working:
    • Ensure iframes have proper CORP headers
    • Check if the iframe content supports COEP
  3. Scripts/stylesheets blocked:
    • Add crossorigin="anonymous" attribute to script/link tags
    • Ensure resources have proper CORS headers
  4. Performance impact:
    • COEP enables process isolation which may affect performance
    • Test with different configurations to find the right balance

Advanced COEP Usage

Combining COEP with COOP for maximum isolation:

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

Dynamic COEP based on content type:

app.use((req, res, next) => {
  if (req.path.endsWith('.html')) {
    res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
    res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
  }
  next();
});

Resource server configuration:

// For resources that need to be embeddable
app.use('/embeddable-resources/*', (req, res, next) => {
  res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
  next();
});