Cross-Origin-Resource-Policy Limits No-CORS Embedding

Many browser elements can request resources across origins without using CORS. Images, scripts, media, and other subresources can travel through no-cors fetch paths where the page does not receive normal script-level access to the response body. That restriction is useful, but an unwanted cross-origin load can still expose a resource to embedding or side-channel conditions.

The Cross-Origin-Resource-Policy response header, commonly shortened to CORP, lets the resource owner state which site relationship is allowed for those no-cors loads.

Cross-Origin-Resource-Policy: same-origin

A supporting browser performs the CORP check on the response. When the request context violates the declared policy, the network request may already have reached the server; enforcement prevents the response body from being delivered to the requesting context. CORP is therefore a response-side isolation control, not a firewall rule that stops packets from reaching an endpoint.

Three values express the resource boundary

CORP accepts three policy values:

Value Intended boundary
same-origin Only the same origin may load the resource through the covered path
same-site Origins in the same site may load it
cross-origin Cross-origin loading is permitted

same-origin is the narrowest choice. It fits private resources that have no legitimate cross-origin embedding requirement.

same-site is broader. It can fit an architecture where sibling origins are intentionally trusted, but that decision deserves scrutiny. A user-content subdomain and an administration subdomain can be same-site while representing very different trust levels.

cross-origin is an explicit sharing signal. It is useful for resources intentionally consumed by unrelated origins and also participates in deployments that use Cross-Origin-Embedder-Policy.

CORP targets no-cors request paths

CORP does not replace CORS. The two mechanisms operate on different request paths and answer different policy questions.

A resource fetched in CORS mode is governed by CORS. A resource loaded through a covered no-cors path can be constrained by CORP. For example, an image element without a CORS opt-in can issue a no-cors request:

<img src="https://assets.example.net/private-chart.png" alt="">

If the response declares:

Cross-Origin-Resource-Policy: same-origin

a document on another origin cannot successfully consume that response through the covered no-cors load.

The request reaching the resource server is an important operational detail. CORP should not be treated as protection against state changes caused merely by receiving a request. Endpoints must still use CSRF defenses and safe HTTP semantics where relevant.

Resource policy differs from document framing policy

CORP is sometimes grouped with headers that control document embedding, but its contract is distinct.

Content-Security-Policy: frame-ancestors controls which ancestors may frame a document. X-Frame-Options provides an older framing restriction. CORP controls whether a resource response can be delivered through covered cross-origin or cross-site no-cors requests.

Using CORP on an HTML response does not make it a substitute for a framing policy. Conversely, a strong frame-ancestors rule does not establish a CORP boundary for images, scripts, or other subresources served by the same application.

Security header sets are easier to audit when each header is tied to the boundary it actually enforces.

Cross-Origin-Embedder-Policy changes the embedding requirements of a document. With Cross-Origin-Embedder-Policy: require-corp, cross-origin resources loaded in no-cors mode need an applicable CORP policy that permits the embedding relationship, unless the load uses CORS and succeeds under CORS rules.

That relationship makes cross-origin meaningful even though it sounds permissive:

Cross-Origin-Resource-Policy: cross-origin

For a public asset server, the header can explicitly state that the resource is intended for cross-origin consumption. A document enforcing COEP can then accept that consent for the relevant no-cors resource load.

This does not mean every resource on the asset origin should receive the same header. Public fonts, private account exports, and authenticated images can require different boundaries even when they share infrastructure.

Apply policy by resource class

A global header can be convenient, but convenience is not a security model. Before rollout, group responses by intended audience.

Private account data, internal JSON endpoints, and origin-local assets are candidates for same-origin when no cross-origin use is required. Shared same-site infrastructure may justify same-site only when every participating origin belongs inside the trust boundary. Public CDN assets can require cross-origin when unrelated sites are expected consumers.

A route inventory can be represented as a small policy table:

/account/export/*     -> same-origin
/app-assets/*         -> same-origin
/shared-branding/*    -> same-site
/public-cdn/*         -> cross-origin

The exact mapping belongs to the application. The important property is that each value follows a documented consumption pattern rather than a blanket header copied across every response.

Compatibility testing includes indirect consumers

Cross-origin dependencies are not always visible in the application repository. Email templates can reference hosted images. Partner pages can embed logos. Documentation can load scripts or media from a shared asset origin. A restrictive CORP rollout can break those consumers even when the primary application still works.

Observation should therefore include request logs, asset ownership, CDN configuration, and known integration paths. Testing should cover browser behavior for the actual element or API that consumes each resource.

PDF delivery deserves additional care. Browser implementations have had compatibility issues involving CORP and PDF rendering, so production policy changes for PDF responses should be tested against the browser set the service supports.

CORP is one isolation layer

CORP strengthens a resource boundary without becoming an authorization mechanism. A response marked same-origin can still be exposed by an application endpoint that returns sensitive data to an unauthorized same-origin caller. Server-side identity and object authorization remain authoritative.

The header also does not repair unsafe state-changing endpoints. Since the request can reach the server before the browser blocks delivery of the body, request-side protections still matter.

Used with precise resource classification, CORP gives the resource owner a browser-enforced statement about no-cors consumption. Its strongest deployments keep that statement narrow, test legitimate embedding paths, and combine it with CORS, framing controls, CSRF defenses, COEP, and authorization only where each mechanism matches the boundary being protected.