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
Cross-Origin-Opener-Policy: same-origin— places the document in its own browsing-context group and setswindow.openertonull. Onlysame-originqualifies;same-origin-allow-popupsdoes not enable isolation.Cross-Origin-Embedder-Policy: require-corp— refuses to load any cross-origin subresource unless it sends a permittingCross-Origin-Resource-Policyheader or passes a CORS handshake.
Every cross-origin asset the isolated page loads must additionally carry, at its own origin:
Cross-Origin-Resource-Policy: cross-origin
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
- Third-party resources need CORP or CORS. Under
require-corp, every cross-origin image, font, script, or iframe must sendCross-Origin-Resource-Policy: cross-origin(or pass CORS with thecrossoriginattribute). Assets on a CDN you do not control, and that do not send CORP, will be blocked and isolation will fail. Audit the Network panel before shipping. The full debugging procedure is in debugging COEP-blocked resources. - The credentialless alternative. If you cannot add CORP to third-party assets, switch to
Cross-Origin-Embedder-Policy: credentialless. It still grantscrossOriginIsolatedbut loads cross-originno-corssubresources without credentials (no cookies). Any cross-origin resource that depends on a cookie — an authenticated image or a personalized widget — will break undercredentialless, so it is a trade, not a free pass. - Popup auth flows break under COOP
same-origin. Becausesame-originsetswindow.openertonull, an OAuth or payment popup that calls back towindow.opener.postMessage(...)will fail.same-origin-allow-popupswould preserve the popup but does not grant isolation — you cannot have bothSharedArrayBufferand an opener-coupled popup on the same document. Move the popup flow to a non-isolated page, or switch to a redirect-based auth flow. - Iframes inherit a requirement. A cross-origin iframe inside an isolated page must itself send COEP
require-corp(orcredentialless) and a permitting CORP, or it is blocked. Embedding third-party iframes in an isolated context usually means coordinating with that provider.
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.