Skip to content

Instantly share code, notes, and snippets.

@yoavweiss
Last active June 18, 2024 08:59
Show Gist options
  • Save yoavweiss/c7b61e97e6f8d207be619f87ab96ead5 to your computer and use it in GitHub Desktop.
Save yoavweiss/c7b61e97e6f8d207be619f87ab96ead5 to your computer and use it in GitHub Desktop.

noopener-allow-popups Cross-Origin-Opener-Policy value

Some origins can contain different applications with different levels of security requirements. In those cases, it can be beneficial to prevent scripts running in one application from being able to open and script pages of another same-origin application. Such a document need to ensure its opener cannot script it, even if the opener document is a same-origin one.

The noopener-allow-popups Cross-Origin-Opener-Policy value severs the opener relationship between the document loaded with this policy and its opener. At the same time, the opened document can open further documents (as the "allow-popups" in the name suggests) and maintain its opener relationship with them, assuming that their COOP policy allows it.

The problem

Let's examine a hypothetical example.com origin that has two very different applications. One is https://example.com/chat that enables any user to contact any other user and send them messages. Another is https://example.com/passwords that contains all of the user's passwords, across different services.

Common security advice to further isolate these applications would be to host them on different origins. But in some cases that's not possible, and those two applications have to be on a single origin for historical/business/branding reasons.

At the same time, the administrators of the "passwords" application would very much like to ensure that it can't be directly scripted by the "chat" app, which by its nature has a larger XSS surface.

So they ask themselves the following question: if we assume that "chat" was compromised, what can prevent the attacker from reading the contents of "passwords"?

They can prevent fetch() calls on "chat" from fetching the "passwords" application HTML directly, by looking at Sec-Fetch-Mode and ensuring its value is "navigate". They can prevent "passwords" from being iframed by "chat" (or anyone) by adding an X-Frame-Options: deny or Content-Security-Policy: frame-ancestors 'none'.

But currently, they can't prevent "passwords" from being opened as a popup or a new tab, and then be scripted by the opener. If that happens, the opener has full access to the "passwords" DOM, and can use that to extract secrets from it!!

Solution: COOP: noopener-allow-popups

By providing a header that enables a document to severe its incoming opener relationship regardless of origin, we can prevent that above abuse scenario.

The opener document who would call window.open() would get back a WindowProxy that would change its closed value to true as soon as the openee document gets assigned to a browsing context group, similar to e.g. a window.open() to a document that redirects across origins.

@arturjanc
Copy link

Assuming we ship this, it would IMO be good to document all of this in the spec to make sure that folks using this COOP mode are aware of these bypasses and required application-level protections. /cc @ArthurSonzogni

For the process model issue in #8 I think we might want to recommend for the browser to separate processes of documents with this value from other same-origin/site renderers (I know the spec doesn't define the process model, but we could add a comment). Otherwise, Spectre-like bugs provide a general bypass of the security properties we want to offer here, i.e. a same-origin XSS could read the data in a document protected with COOP noopener-allow-popups.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment