Enabling Cross-Origin Isolation for SharedArrayBuffer

This page is a focused procedure under the Cross-Origin Isolation: COOP, COEP & CORP reference. SharedArrayBuffer, WebAssembly threads, performance.measureMemory(), and unclamped high-resolution timers are all gated behind the crossOriginIsolated flag. That flag flips to true only when the top-level document sends the exact pair of headers below and every cross-origin subresource opts in. This is the precise configuration to get there.

Configuration Syntax & Exact Values

Two headers on the top-level document, with no quotes and no extra tokens:

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

Every cross-origin asset the isolated page loads must additionally carry, at its own origin:

Cross-Origin-Resource-Policy: cross-origin
The gate from COOP and COEP to SharedArrayBuffer A left-to-right flow showing COOP same-origin and COEP require-corp combining into crossOriginIsolated true, which enables SharedArrayBuffer and Wasm threads. COOP same-origin COEP require-corp crossOriginIsolated === true SharedArrayBuffer Wasm threads enabled
Both headers must hold simultaneously; either one missing leaves crossOriginIsolated false and SharedArrayBuffer undefined.

Server-Side Configuration

Nginx

location / {
    add_header Cross-Origin-Opener-Policy "same-origin" always;
    add_header Cross-Origin-Embedder-Policy "require-corp" always;
}

# First-party assets the isolated page embeds
location ~* \.(js|wasm|woff2|png|jpg)$ {
    add_header Cross-Origin-Resource-Policy "same-origin" always;
}

The always flag ensures the headers survive on error responses so navigating to a 404 does not silently drop isolation. First-party assets can use same-origin for CORP; only genuinely cross-origin assets need cross-origin.

Apache (mod_headers)

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

<FilesMatch "\.(js|wasm|woff2|png|jpg)$">
  Header always set Cross-Origin-Resource-Policy "same-origin"
</FilesMatch>

always applies the headers across all status codes; the default onsuccess table would skip errors. Requires mod_headers.

Cloudflare (Transform Rules)

Rules → Transform Rules → Modify Response Header → Set static:
  When URI Path equals /app    (the isolated document)
    Cross-Origin-Opener-Policy   = same-origin
    Cross-Origin-Embedder-Policy = require-corp
  When URI Path matches static assets
    Cross-Origin-Resource-Policy = cross-origin

Use Set, not Add, so the edge does not stack a duplicate header on an origin-set one.

Node/Express (Helmet)

const helmet = require('helmet');

app.use(
  helmet({
    crossOriginOpenerPolicy: { policy: 'same-origin' },
    crossOriginEmbedderPolicy: { policy: 'require-corp' },
    crossOriginResourcePolicy: { policy: 'same-origin' },
  })
);

Mount the middleware before your routers so every response — including errors — carries the headers.

Diagnostic & Verification Steps

Confirm the document headers, then confirm the runtime flag.

curl -sI https://your-domain.com/app | grep -iE 'cross-origin-(opener|embedder)-policy'
# Expected:
#   cross-origin-opener-policy: same-origin
#   cross-origin-embedder-policy: require-corp

In the browser DevTools Console on the loaded page:

self.crossOriginIsolated
// Expected: true

typeof SharedArrayBuffer
// Expected: "function"

If self.crossOriginIsolated is true, SharedArrayBuffer is constructable and Wasm threads will instantiate. If it is false, open DevTools → Network and look for requests blocked with reason (blocked:NotSameOriginAfterDefaultedToSameOriginByCoep) — those are subresources missing CORP. The Application → Frames → top → Security & isolation panel reports the computed COOP/COEP state and the reason isolation was denied.

Edge Cases, Security Implications & Safe Rollback

These headers do not delete data or lock you out the way HSTS preload does, so rollback is low-risk: remove COEP only while keeping COOP same-origin to retain the opener-severance defense:

Header unset Cross-Origin-Embedder-Policy
Header always set Cross-Origin-Opener-Policy "same-origin"

Removing COEP disables SharedArrayBuffer but leaves your XS-Leak hardening intact. Prefer switching to credentialless before a full removal.

Frequently Asked Questions

Is COOP same-origin-allow-popups enough for SharedArrayBuffer? No. Only same-origin enables cross-origin isolation. same-origin-allow-popups preserves opener-coupled popups but leaves self.crossOriginIsolated false, so SharedArrayBuffer stays undefined.

Do first-party scripts on the same origin need CORP? Same-origin subresources are not blocked by COEP require-corp, so strictly they do not need CORP to load. Setting Cross-Origin-Resource-Policy: same-origin on them is still good practice to stop other sites embedding them.

My Wasm module fails to instantiate threads — why? Wasm threads require SharedArrayBuffer, which requires crossOriginIsolated === true. Check that flag first; if it is false, a subresource is blocked or COOP is not exactly same-origin.

Can I enable isolation only on one route? Yes. COOP and COEP are per-document. Apply them only to the route that needs SharedArrayBuffer (scope the Nginx location or Cloudflare path match), leaving the rest of the site non-isolated so popup and third-party flows elsewhere keep working.

Conclusion

Roll out incrementally: set COOP and COEP on a staging copy of the target route, open it and confirm self.crossOriginIsolated === true with no blocked subresources in the Network panel, then promote to production. If third-party assets block isolation and you cannot add CORP, fall back to credentialless rather than abandoning isolation. Keep COOP same-origin even if you drop COEP, so the opener-severance defense survives.