Glossary
Cross-Origin-Resource-Policy
`Cross-Origin-Resource-Policy` is a response header by which a resource declares which origins are allowed to load it at all — not to read it, which is CORS, but to embed it. It exists because loading a resource cross-origin, even without reading it, leaks information through side channels: whether it exists, how large it is, how long it took. It is the mechanism a resource uses to opt out of being embedded by strangers.
The three values
`same-origin` — only the exact origin that served it may load it.
`same-site` — the registrable domain and its subdomains may load it.
`cross-origin` — anyone may. This is what a public CDN asset or a deliberately embeddable resource declares.
Absent the header, the default behaviour depends on the context: a document embedding under a strict embedder policy requires the header, and ordinary embedding does not.
`same-site` is a weaker guarantee than it sounds: it is based on the registrable domain, so any subdomain qualifies, including one an attacker might control on a shared hosting domain.
How it differs from CORS
CORS decides whether a page may read a response it requested. CORP decides whether the request may be made as a subresource embedding at all.
CORS is opt-in permission to read; CORP is opt-out of being embedded.
They address different halves of the same boundary, and a resource can sensibly set both: a CORS policy for its API consumers and a CORP policy for how it may be embedded.
A resource blocked by CORP produces a network error rather than a read failure, which is why the symptoms differ in the console.
A resource can also satisfy an embedder policy through CORS instead of CORP, by being requested in a mode that performs a CORS check — which is the route an API takes when it already has CORS configured.
Why side channels made it necessary
Even an unreadable cross-origin resource reveals things: whether it loaded successfully tells you whether it exists, and how long it took can indicate whether it came from a cache.
Combined with speculative execution attacks, an embedded resource's bytes could in principle be read from the same process.
Process isolation by site is the structural defence, and CORP is how a resource states it does not want to be placed in another site's process.
`Cross-Origin-Embedder-Policy: require-corp` inverts the question: a document with that policy refuses to embed anything that has not explicitly opted in.
What to set on what
Application resources not meant to be embedded elsewhere: `same-origin`.
Assets shared across your own subdomains: `same-site`.
Public assets on a CDN, embeddable images, widget scripts: `cross-origin`, which is required for them to work under a strict embedder policy.
Check the console for CORP errors after adopting an embedder policy; the resources that need `cross-origin` announce themselves immediately.
Fonts and images loaded from a third party are the usual blockers, and whether they can be fixed depends on that third party setting the header, which is a reason to self-host what you can.
Frequently asked questions
- What is the difference between CORP and CORS?
- CORS grants permission to read a response. CORP decides whether a resource may be embedded by another origin at all.
- Which value should my images use?
- cross-origin for public assets meant to be embedded anywhere, same-origin for anything belonging to the application itself.
- Do I need CORP if I am not using cross-origin isolation?
- It is optional, and it is a cheap way for a resource to decline being embedded elsewhere. It becomes required when an embedding document sets require-corp.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website