Cross Origin Isolation

Cross-Origin Isolation aims to protect sites from side-channel attacks such as Spectre by defining opt-in rules that allow a user agent to place pages in specially restricted origin-keyed processes. See this article for more background. Developers can enable Cross-Origin Isolation by setting both the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers.

This document will outline how Cross-Origin Isolation is represented in specifications, and how that is translated into the Chromium codebase.

Cross-Origin Isolation in Specifications

At the time that Cross-Origin Isolation (COI) was designed, all major browsers could put top-level documents in dedicated processes, but not all browsers supported out-of-process iframes. Because of this, COI had to be designed to provide side-channel attack mitigation while cross-origin child frames were running in the same process as the main frame. Much of its complexity comes from this requirement.

The Cross-Origin Isolation state of agents is represented by the “cross-origin isolation mode” of their browsing context group (BCG), which can have one of three values: none (non-isolated), logical, or concrete. “None” is the default value and will be used in content that doesn’t set the headers needed to opt-in to COI. A BCG will have the “logical” isolation mode if its agent clusters cannot have dedicated processes due to resource or implementation constraints, and “concrete” if they can. All restrictions imposed by the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers will still apply to documents in logically isolated BCGs, but they will not have the cross-origin isolated capability (explained below). The remainder of this document will ignore the logical isolation mode.

BCGs with logical or concrete Cross-Origin Isolation modes are considered to be Cross-Origin Isolated, and will be referred to as Cross-Origin Isolated Browsing Context Groups (COI BCGs) in this document. All top-level documents or workers in a COI BCG must be same-origin.

If COI is enabled through the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers, then the latter header requires any cross-origin resource loaded within the COI BCG to opt-in to cross-origin embedding via the Cross-Origin-Resource-Policy header. This header is needed because in browsers without out-of-process iframes, cross-origin content embedded in a COI page would be vulnerable to side-channel attacks from the embedding page. The header limitations ensure that COI documents cannot use side-channel attacks (e.g., Spectre-related vulnerabilities using high precision timer APIs) to leak cross-origin content, unless that content has acknowledged the risk via the CORP header.

Cross-Origin Isolated Capability

Concrete Cross-Origin Isolation guarantees that no cross-origin content is running in a document's process unless it opted-in through the Cross-Origin-Resource-Policy header. This allows user agents to safely expose APIs that could be used to perform side-channel attacks because there is no in-process cross-origin content for the document to leak.

Due to the issue described in github.com/whatwg/html/issues/5435, there’s also a policy-controlled feature required to grant access to COI-gated APIs. Frames that are missing the “cross-origin-isolated” feature will not be able to use COI-gated APIs, but COI-related restrictions will still apply to them. Agents that are allowed to use COI-gated APIs have the “cross-origin isolated capability.” To summarize yhirano@’s response on that issue, there are 3 concepts at play here:

  • Cross-Origin Isolation mode - this refers to whether the aforementioned COI restrictions are in place for a given browsing context group.
  • “cross-origin-isolated” feature - this refers to “cross-origin-isolated” policy-controlled feature. Top-level frames are granted this feature by default but may choose to deny it to child frames. Note that despite its name, this doesn’t actually control whether a frame can request or be given cross-origin isolation, only whether APIs that require cross-origin isolation can be enabled.
  • Cross-Origin Isolated capability / window.crossOriginIsolated - this is a boolean global property representing an agent’s COI capability, which controls whether COI-gated APIs are available. This is equal to COI mode && COI feature.

COI-gated APIs are only available when the window.crossOriginIsolated property is true, and can be blocked in child frames by not delegating the COI feature.

All frames and workers within a BCG will have the same COI mode. Child frames in a COI BCG will not have the COI capability (self.crossOriginIsolated === false) if the “cross-origin-isolated” feature was not delegated to them. Two same-origin frames in the same BCG with different COI capabilities are still synchronously scriptable. This means a same-origin child frame without the COI capability could access COI-gated APIs via its parent document, which is the intended behavior. This would be a security issue for most policy-controlled features, which are intended to block access to capabilities, but “cross-origin-isolated” is a bit more subtle. These APIs are not inherently dangerous; they're only a threat to cross-origin content running in the same process. The goal of the “cross-origin-isolated” feature is not to completely block access to COI-gated APIs, but instead to allow blocking access to them in cross-origin iframes, which in browsers without out-of-process iframes would have to run in-process. This allows embedding frames to protect themselves from side-channel attacks from cross-origin embedded content.

Worker behavior depends on the type of worker:

  • Service Workers will have the COI capability if their worker script's response sets the appropriate Cross-Origin-Embedder/Opener-Policy headers for non-local schemes, or will inherit the COI capability of their creator for local schemes (about, blob, data, filesystem, etc…). Permissions Policy doesn’t apply to workers because it’s a document-level concept (see github issue), so it can’t be taken into account here. See step 14.3.4 in section 10.2.4 of the spec.
  • Shared Workers and Shared Storage Worklets do not currently support COI.
  • Dedicated Workers and Worklets have the COI capability if their hosting document does.

Isolated Contexts

Isolated Contexts are environments which meet a minimum bar of isolation and integrity verification, and are used to gate APIs that are too powerful to expose in Secure Contexts, and require review/attestation. They are the security foundation of Isolated Web Apps. Isolated Contexts require COI, but do not directly extend it at a specification level.

Document-Isolation-Policy

Document-Isolation-Policy builds on and extends the concepts introduced by Cross-Origin Isolation to allow documents to opt-in to COI without the restrictions imposed by COOP/COEP. This document doesn't yet cover the specification or implementation details of Document-Isolation-Policy.

Cross-Origin Isolation in //content

WebExposedIsolationInfo

WebExposedIsolationInfo (WEII) represents a browsing context group’s cross-origin isolation mode, and does not take into account the “cross-origin-isolated” policy-controlled feature. Note in the diagram below that all iframes have the same WEII value regardless of their origin or Permissions Policy.

WEII is a non-public class in //content, and is the source of truth for the COI mode of a given BCG. It is a property of BrowsingInstance (//content’s representation of a BCG) and ProcessLock, and can have a value of “not isolated”, “isolated”, or “isolated application.” In the latter two cases it will also contain the origin representing the isolation boundary. The origin is necessary to ensure that documents from the same site embedded within two cross-origin COI pages will never be placed in the same process.

As mentioned above, Isolated Contexts aren’t an extension of the Cross-Origin Isolated mode at the specification level, but they are at the //content level. The “isolated application” WEII represents Isolated Contexts. Long term the “isolated application” WEII to Isolated Context mapping should be 1:1, but for now Chrome Apps are also considered Isolated Contexts because they need access to these APIs but predate Cross-Origin Isolation and often don't work with it enabled.

WebExposedIsolationLevel

WebExposedIsolationLevel (WEIL) is a public enum in //content that, like WEII, has three values: kNotIsolated, kIsolated, and kIsolatedApplication. It represents the cross-origin isolated capability of a specific frame if accessed from RenderFrameHost::GetWebExposedIsolationLevel(), or the cross-origin isolated mode of a process if accessed from RenderProcessHost::GetWebExposedIsolationLevel(). Unlike kIsolated, kIsolatedApplication will not propagate to cross-origin child frames; they will have at most the kIsolated WEIL.

This means that WEIL and WEII will differ in workers or iframes if their process is locked to a different origin than the WEII, and will differ in frames if the “cross-origin-isolated” feature was not delegated to the frame.

Diagram of WEII vs WEIL

Guarding APIs on Isolation Level

API access should be guarded on RenderFrameHost::GetWebExposedIsolationLevel(), which takes permissions policy into account, when a RenderFrameHost is available. Shared and Service Workers don’t have a RenderFrameHost, so they need to use RenderProcessHost::GetWebExposedIsolationLevel() to check their isolation mode. This does mean permissions policy will be ignored, which is the expected behavior.

Isolation Level Representation in Blink

The application isolation level maps to “Isolated Context” in Blink. APIs can be limited to this isolation mode by adding the [IsolatedContext] IDL attribute, which reflects the static Agent::IsIsolatedContext(), which itself reflects the process’s WEIL. There’s also ExecutionContext::IsIsolatedContext(), which maps to Agent::IsIsolatedContext(). Checking API availability in Blink currently requires checking both ExecutionContext::IsIsolatedContext() and ExecutionContext::CrossOriginIsolatedCapability().

Appendix

Other useful resources: