Why powerful browser features demand cross-origin isolation
Certain modern browser APIs — SharedArrayBuffer, precise high-resolution timers, and performance.measureUserAgentSpecificMemory() — are only available when your page operates in a state called cross-origin isolated. This article explains what that state means, why the browser demands it, and which HTTP headers establish it.
The problem: same-origin policy leaks
The web's core security model is the same-origin policy, which stops a document from one origin reading data from another. But the policy has always had sanctioned exceptions: any site can embed cross-origin iframes, load cross-origin images or scripts, and open cross-origin popup windows with a live DOM reference. By the time browsers needed a stricter model, these exceptions were already baked into the platform.
Two mechanisms patched the holes those exceptions created:
- CORS lets a server explicitly allow a resource to be shared with a given origin.
- Resources loaded without permission become opaque — the requesting script cannot inspect their contents. That is why drawing a cross-origin image to a
CanvasRenderingContext2Dand reading pixels back fails unless CORS is applied.
Both mechanisms operate within a browsing context group — the set of windows and iframes that share a process and can reference each other.
That combination held until Spectre. Spectre attacks measure the timing of CPU operations to infer the contents of process memory — potentially any data loaded into the same browsing context group. Low-granularity timers make such attacks possible; high-granularity timers, like performance.now(), make them practical. If evil.com embeds a cross-origin image, it can use Spectre to read that image's pixels, regardless of whether the image was opaque.
The remedy: cross-origin isolation
The defensible fix is to make sure every cross-origin resource reaching your code has been vetted by its owner via CORS or CORP. If a resource hasn't been granted permission, it never enters the browsing context group at all, so no Spectre attack can read it. A page that enforces this discipline is cross-origin isolated.
In exchange for that stricter state, the browser enables SharedArrayBuffer, performance.measureUserAgentSpecificMemory(), high-resolution timers with better precision, and it disallows modifying document.domain.
Two headers work together to establish the state: COEP and COOP.
COEP: Cross Origin Embedder Policy
Cross Origin Embedder Policy (COEP) prevents a document from loading any cross-origin resource unless that resource explicitly grants permission via CORS or CORP. The header accepts a single value:
Cross-Origin-Embedder-Policy: require-corp
With require-corp, the document may load only same-origin resources and cross-origin resources that opt in.
Cross-origin resources can opt in two ways:
- CORS — When loading the resource with the
crossoriginattribute (for images, scripts, or styles) or withfetch(), the request runs in CORS mode. If the server responds with the appropriate CORS headers, the resource is permitted. - CORP — The Cross Origin Resource Policy header declares which origins may load a resource. It was originally an opt-in protection; under COEP it becomes the server's stated loading policy. Its three values are:
Cross-Origin-Resource-Policy: same-site
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Resource-Policy: cross-origin
same-siterestricts loading to the same site.same-originrestricts loading to the same origin.cross-originpermits any website to load the resource — a value added to the CORP spec alongside COEP.
COOP: Cross Origin Opener Policy
Cross Origin Opener Policy (COOP) separates a top-level document from other windows by placing it in its own browsing context group. When a document sets COOP, popups it opens can no longer interact with it through window.opener: the property becomes null on the popup, and .closed on the opener's reference becomes true.
The header accepts three values:
same-origin— The document shares a browsing context group only with same-origin documents that also setsame-origin.same-origin-allow-popups— The top-level document keeps references to popups that either set no COOP or deliberately useunsafe-none.unsafe-none— The default. The document joins its opener's browsing context group, unless the opener itself sets COOPsame-origin.
Putting it together
To qualify for SharedArrayBuffer, performance.measureUserAgentSpecificMemory(), or higher-precision timers, your document must send both:
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
If either is missing, the browser cannot guarantee the isolation those features require. You can check your page's status with self.crossOriginIsolated; it returns true only when both headers are present and the page is fully isolated.
For step-by-step implementation details, see the companion guide on enabling cross-origin isolation with COOP and COEP.



