Same-origin policy

On this page 7

The same-origin policy is the fundamental browser security model that restricts how a document or script loaded from one origin can read data from or interact with resources of another origin. An origin is the combination of scheme, host and port, and two URLs share an origin only when all three match exactly.

Among browser technologies, the same-origin policy is the reason a malicious page cannot silently read a user’s webmail or bank account in another tab, even though the browser holds valid session cookies for those sites. It does not block every cross-origin request; it mainly blocks reading the responses, while controlled exceptions such as CORS let servers opt in to sharing their data.

How browsers define an origin

An origin is compared as a tuple of scheme, host and port. The path, query string and fragment play no role. If any part of the tuple differs, the browser treats the two URLs as different origins.

The table below compares several addresses with the origin formed by HTTPS, the host shop.example.com and the default HTTPS port 443.

Compared addressSame originReason
shop.example.com/cart over HTTPSYesOnly the path differs
shop.example.com/help over HTTPS on port 443Yes443 is the default HTTPS port
shop.example.com over plain HTTPNoDifferent scheme
api.example.com over HTTPSNoDifferent host, even within the same site
shop.example.com over HTTPS on port 8443NoDifferent port
Origin comparison with an HTTPS page on shop.example.com

Browsers also use the broader concept of a site, defined as the scheme plus the registrable domain. The subdomains shop.example.com and api.example.com are same-site but cross-origin. This distinction matters because cookie rules such as SameSite work at the site level, while the same-origin policy works at the stricter origin level.

What the policy allows and what it blocks

The policy is often misunderstood as a ban on all cross-origin communication. In reality, the web depends on embedding resources across origins, and the policy primarily protects the confidentiality of responses.

InteractionDefault behaviorExample
Embedding resourcesGenerally allowedImages, scripts, stylesheets, video and iframes from other origins
Sending navigations and form postsAllowedA link or form targeting another site
Reading fetch or XHR responsesBlocked unless CORS permitsScript reading JSON from another API
Accessing another frame’s DOMBlockedScript reading content of a cross-origin iframe
Reading storageIsolated per originlocalStorage, IndexedDB and cache storage
Reading canvas pixels from foreign imagesBlocked after the canvas is taintedgetImageData on a cross-origin image
Cross-origin interactions under the same-origin policy

Because cross-origin requests can still be sent, the same-origin policy alone does not prevent cross-site request forgery. A hostile page can submit a form to another site with the user’s cookies attached. Defenses such as SameSite cookies and anti-forgery tokens address that separate threat.

Controlled exceptions and relaxations

Legitimate applications often need cross-origin access, for example a web front end on one origin calling an API on another. Browsers provide explicit, opt-in mechanisms for these cases.

MechanismHow it worksTypical use
CORSServer returns Access-Control-Allow-Origin and related headersAPIs consumed by front ends on other origins
postMessageWindows exchange messages and verify the sender originCommunication with embedded iframes or popups
Preflight requestBrowser sends OPTIONS before non-simple requestsRequests with custom headers or methods such as PUT
Credentialed CORSAllow-Credentials true with a specific origin, never a wildcardCookie-authenticated cross-origin APIs
Reverse proxyRequests routed through the same originAvoiding cross-origin calls altogether
Mechanisms for permitted cross-origin access

CORS relaxes the policy only for reading, and the server, not the client, decides. A response with Access-Control-Allow-Origin: * is readable by any origin but cannot be combined with credentials. Changing the client code cannot bypass a missing CORS header, which is why CORS errors must be fixed on the server.

The older technique of setting document.domain to a shared parent domain is deprecated and being removed from browsers, because it weakened origin isolation. The JSONP pattern, which loaded data as executable scripts, has likewise been replaced by CORS for security reasons.

Modern browsers reinforce the same-origin policy with additional isolation layers. These were strengthened after side-channel attacks such as Spectre showed that data in the same process could leak across origins.

  • Site isolation places documents from different sites in separate operating system processes, inside the browser sandbox.
  • Cross-Origin Resource Policy lets a server state that a resource may only be loaded by the same site or origin.
  • Cross-Origin Opener Policy and Embedder Policy together enable cross-origin isolation, which is required for powerful features such as SharedArrayBuffer.
  • Content Security Policy restricts which origins a page may load scripts and other resources from, limiting the impact of injected code.

These mechanisms complement each other. The same-origin policy defines what scripts may read, while process isolation ensures that a compromised renderer cannot simply read another origin’s memory.

Common misconceptions and mistakes

Developers usually meet the same-origin policy as an error message, which leads to misguided workarounds. The most frequent misunderstandings are listed below.

  • Treating CORS errors as client bugs: the fix is a correct header on the server or a same-origin proxy.
  • Reflecting any Origin header with credentials allowed, which effectively disables the protection for authenticated data.
  • Assuming subdomains are trusted: api.example.com and shop.example.com are different origins.
  • Using postMessage without checking event.origin, which lets any page send commands to the receiving window.
  • Believing the policy stops CSRF, when it only protects reading responses.

In plain words

The same-origin policy is a rule that keeps websites out of each other’s business. A page from one website can show pictures from another site. It cannot quietly read private information from that site.

Imagine having your email open in one tab and a strange website in another. That website cannot read your inbox, even though your browser is logged in. Each website stays inside its own box unless the other site openly allows sharing.

A real-world example

A company hosts its single-page application on app.example.com and its API on api.example.com, both over HTTPS. After launch, the browser console shows CORS errors for every request, because the two hosts are different origins and the API returns no CORS headers. A developer first suggests a browser extension that disables the check, which would only hide the problem on one machine.

The backend team instead configures the API to return an Access-Control-Allow-Origin header naming the application origin exactly, together with Access-Control-Allow-Credentials: true, and to answer preflight requests for PUT and DELETE. Requests from the application now succeed, while scripts on any other origin still cannot read the API responses, so authenticated customer data remains protected.