Same-origin policy
SOP · /seɪm ˈɒrɪdʒɪn ˈpɒlɪsi/
The same-origin policy is the browser's default security rule: JavaScript running on one origin cannot read responses, DOM, or storage belonging to another origin. CORS is the standard way for a server to explicitly opt out of this restriction for specific origins.
Why it exists
Without it, any website you opened could quietly issue requests to your bank, your email, or your company's intranet — using your browser's existing session cookies — and read the responses. The web simply wouldn't be safe to browse with multiple tabs open.
The same-origin policy is the reason logging into Gmail in one tab doesn't let a malicious page in another tab read your inbox. The malicious page can still send requests (your browser will include the cookies), but it can't read the response.
What it actually restricts
- Reading responses from another origin via
fetch/XMLHttpRequest— blocked unless CORS allows it. - Reading the DOM of a cross-origin
<iframe>— blocked. - Reading
localStorage,sessionStorage, IndexedDB — each origin has its own scoped storage. Cross-origin code can't touch it. - Reading pixels from a cross-origin
<canvas>after a tainted draw — the canvas becomes locked.
What it allows anyway
Several things were allowed before the same-origin policy existed and stayed allowed for backwards compatibility:
- Embedding cross-origin
<img>,<script>,<link>,<video>,<iframe>. The browser renders them but blocks JS from reading the bytes. - Submitting cross-origin forms. (This is why CSRF tokens exist — the request itself isn't blocked, just the response read.)
- Navigating the browser to a cross-origin URL via clicks or
window.location.
Same origin vs same site
A subtler distinction the browser also tracks: "same site" is laxer. app.example.com and api.example.com are different origins (different host) but the same site (same registrable domain). Newer cookie attributes like SameSite=Strict use the site boundary; CORS and the same-origin policy use the origin boundary.