CentralCSP
Security headers

Cross-Origin-Resource-Policy

CORP lets a resource say who may embed it, protecting against cross-origin leaks and hotlinking. Values and how it pairs with COEP.

Last update:

Everything your server publishes is embeddable by default. Any page on the web can point an <img>, <script>, or <video> tag at your URLs and the browser fetches the resource straight into that page's process. Cross-Origin-Resource-Policy (CORP) is a response header a resource sends to say who may load it: only its own origin, only its own site, or anyone.

It is the inverse of Cross-Origin Resource Sharing (CORS): CORS lets a server opt in to other origins reading its responses, while CORP lets a resource opt out of being embedded by them.

The strictest setting keeps a resource for the origin that served it:

Cross-Origin-Resource-Policy: same-origin

Values and what each does

ValueStatusDescription
same-origin✅ GoodOnly requests from the exact same origin (scheme, host, and port) receive the resource. The default-deny choice for private assets.
same-site✅ GoodRequests from the same registrable domain pass, subdomains included, with one scheme rule: an HTTP page cannot load an HTTPS resource this way.
cross-origin✅ GoodAny origin may load the resource. For truly public assets only; it exists mainly so pages behind COEP require-corp can still load them.

A missing header behaves like cross-origin: the resource stays loadable by everyone. So does a value the browser cannot parse. Anything other than these three keywords is treated as if no header were sent, so a typo silently turns the protection off.

CORP does not stop the request. The browser sends it, your server answers, and only then does the browser check the header and, on a mismatch, withhold the body and fail the load with a network error. The resource never enters the embedding page's process, but the request still reached your server.

The check applies only to no-cors requests, the default mode for <img>, <script src>, <audio>, <video>, and stylesheets loaded without a crossorigin attribute. A request made in CORS mode skips the CORP check, because CORS already requires an explicit grant from the server. Requests from the resource's own origin always pass, whatever the value. And CORP does not block top-level navigations or plain <iframe> embeds on its own; iframe responses are CORP-checked only when the embedding document enforces COEP require-corp.

What it protects against

  • Spectre-class side channels. CORP was revived in 2018, from the older From-Origin proposal, in response to Spectre and Meltdown. Those attacks let a malicious page read any data that shares its process, including cross-origin resources it embedded. CORP keeps your resource out of the attacker's process in the first place, so there is nothing to read.
  • Cross-site script inclusion (XSSI). A script marked same-origin or same-site cannot be pulled in by another site's <script> tag, closing off attacks that include your scripts to read the data they carry.
  • Hotlinking. Supporting browsers refuse to render your images and media on other sites. Note the limit: non-browser clients ignore the header, so this is embedding control, not bandwidth protection.

Browsers already enforce a default floor here. Opaque Response Blocking (ORB) blocks no-cors reads of clearly-data responses (HTML, JSON, XML, PDFs, archives) with no header needed, but it deliberately lets JavaScript, CSS, images, and media through so existing sites keep working. The ORB explainer strongly encourages protecting those pass-through resource types with Cross-Origin-Resource-Policy when they contain anything sensitive. Treat ORB as the default and CORP as the explicit control for what it lets through.

The COEP connection

Cross-Origin-Embedder-Policy (COEP) is the other half of the pair, and its own page covers it in full. A document that enforces Cross-Origin-Embedder-Policy: require-corp only loads cross-origin subresources that opt in, and it treats a missing or malformed CORP header as same-origin. That flipped default is what blocks unlabeled third-party assets, and it is why any host serving genuinely public assets (a CDN, a widget, a font service) must send Cross-Origin-Resource-Policy: cross-origin to stay embeddable in isolated contexts.

One gotcha catches many rollouts: adding Access-Control-Allow-Origin to a no-cors response does not satisfy require-corp. Either the embedding element makes a real CORS request (a crossorigin attribute), or the resource sends CORP. COEP's credentialless value is the alternative that loads CORP-less cross-origin resources by stripping credentials from the request.

Risks without it

Any site can pull your assets into its own process. A page you have never heard of can embed the avatars, charts, or documents your server returns for logged-in users, then use a speculative-execution side channel to read them. It can include your scripts with a <script> tag and observe what they expose (XSSI). And it can hotlink your images and media, serving your content in its own pages. ORB blocks only the clearly-data cases; everything else rides on the cross-origin default until you send the header.

Risks and gotchas when using it

  • same-origin breaks multi-subdomain setups. Assets served from cdn.example.com and consumed by www.example.com are cross-origin to each other, so same-origin blocks them. Use same-site when subdomains share assets.
  • The HTTPS edge case in same-site. The requester's scheme matters: an HTTP page cannot load an HTTPS resource marked same-site, even on the same registrable domain. This is the specified and implemented behavior, even though some documentation prose omits it.
  • Overmarking public assets breaks consumers. Setting same-origin or same-site on assets other sites are meant to load breaks every third-party consumer, including any page that enforces COEP require-corp. Those assets need cross-origin.
  • Safe to deploy everywhere. Browsers without CORP support ignore the header, so shipping it carries no compatibility risk.
  • It pairs well with server-side isolation. CORP is enforced by the browser after the response arrives. Rejecting unwanted requests on the server with Fetch Metadata (for example, refusing Sec-Fetch-Site: cross-site) complements it.

How to set it up

  1. Classify what you serve into three buckets: private assets used by one origin, assets shared across your subdomains, and public assets meant for other sites.
  2. Set the header per bucket: same-origin on private assets, same-site on subdomain-shared assets, cross-origin only on the public ones.
  3. If any of your pages will enable COEP require-corp, load them with the new headers in place and confirm every subresource still arrives; a resource you overmarked in step 2 fails there first.
  4. Check the deployed header, and the rest of your response headers, with the security headers scanner.

Recommendation

Send Cross-Origin-Resource-Policy: same-site as the default for your own assets:

Cross-Origin-Resource-Policy: same-site

The OWASP HTTP Headers cheat sheet recommends same-site, limiting resource loading to your site and its subdomains. Treat it as the ceiling, not the floor: prefer same-origin wherever subdomains do not need the asset, and relax to cross-origin only on assets other sites are meant to load, including COEP-isolated ones.

Browser support

Supported across current Chrome, Edge, Firefox, and Safari. Browsers without support ignore the header, so there is no downside to sending it everywhere.

FAQ

What is the difference between CORP and CORS?

They are inverses. CORS is opt-in: a resource uses it to let other origins read its content. CORP is opt-out: a resource uses it to declare who may embed it cross-origin. CORP only governs no-cors requests, the default mode of images, scripts, and media, while CORS-mode requests skip the CORP check entirely.

What is the difference between CORP and COEP?

CORP is set by the resource and says who may load it. COEP is set by the embedding page and says it will only load resources that opt in. A missing CORP header is treated as same-origin under COEP require-corp, which is what blocks unlabeled third-party assets. See CORP vs COEP for the full comparison.

Does CORP block hotlinking?

In browsers, yes. A cross-origin no-cors load of a resource marked same-origin or same-site fails with a network error, so another site cannot embed your image or script. Non-browser clients ignore the header, though, so treat CORP as embedding control against browsers, not as bandwidth or theft protection.

See also

Sources

On this page