Same-Origin Policy
Origin tuple (scheme/host/port), what SOP blocks, and how CORS, postMessage, and cookies relate.
- browser
- same-origin-policy
- security
- cors
The same-origin policy (SOP) is the browser’s primary isolation rule: code from origin A doesn’t freely read origin B’s data. Without it, any site you visit could fetch your bank’s JSON with your cookies and exfiltrate it. CORS, cookies SameSite, and postMessage are controlled exceptions — not replacements.
Docs: MDN Same-origin policy, HTML Living Standard origin.
What is an origin?
origin = scheme + host + port
| URL A | URL B | Same origin? |
|---|---|---|
https://a.com/x |
https://a.com/y |
Yes |
https://a.com |
http://a.com |
No (scheme) |
https://a.com |
https://www.a.com |
No (host) |
https://a.com |
https://a.com:443 |
Yes (default port) |
https://a.com:3000 |
https://a.com:3001 |
No (port) |
Same site (eTLD+1 / schemeful site for cookies) is a different, coarser notion used by SameSite cookies.
What SOP actually blocks
- Reading cross-origin DOM (
iframe.contentDocument) when not same origin - Reading cross-origin
fetch/XHR responses without CORS - Reading cross-origin canvas pixels in many tainted cases
What still works without CORS:
- Embedding many resources (
<img>,<script src>, form POST navigations) - Sending requests that the browser will fire (side effects may still occur server-side!)
SOP is about confidentiality of responses to script, not a server-side firewall. CSRF exists because browsers still send cookies on some cross-site requests — CSRF for SPAs.
Controlled escapes
| Mechanism | Purpose |
|---|---|
| CORS | Server opts in to response reading |
| postMessage | Structured cross-window messaging |
| window.opener / frames | Limited cross-window refs with care |
| JSONP (legacy) | Old script-tag bypass — avoid |
// CORS-enabled read
const res = await fetch('https://api.example.com/me', { credentials: 'include' });
// requires ACAO + credentials rules
// postMessage
otherWindow.postMessage({ type: 'hello' }, 'https://partner.example');
Always verify event.origin on message — postMessage security.
Storage isolation
localStorage, IndexedDB, and cookies (with host rules) are origin-scoped (cookies have their own domain/path model). Subdomains do not share localStorage.
Interview out-loud
“SOP isolates scheme+host+port so scripts can’t read other origins’ DOM or responses. Embedding and request sending still happen; CORS and postMessage are explicit opt-ins. Same-site cookies are a separate concept for CSRF.”
Same-site vs same-origin (say it cleanly)
https://app.example.com and https://api.example.com are same-site (schemeful site) but cross-origin. Cookies can be shared with Domain attributes; localStorage cannot. CORS is required for JS to read API responses. Mixing the terms loses interview points and leads to wrong CSRF fixes.
Related
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
- Same-origin policy — MDN
- Browser Security Handbook concepts (historical but insightful)
Related guides
- CORS Explained for FrontendWhy the browser blocks cross-origin responses, what Access-Control-* headers mean, preflight, credentials, and how to fix real frontend errors.
- Content-Type and MIME SniffingWhy Content-Type matters, how MIME sniffing works, X-Content-Type-Options: nosniff, and XSS-ish pitfalls.
- Cross-Origin Embedder PolicyCOEP require-corp / credentialless: cross-origin isolation, SharedArrayBuffer, and embedding requirements.
- Cross-Origin Opener PolicyCOOP same-origin and same-origin-allow-popups: sever window.opener, process isolation, and OAuth popups.
- Feature Policy Legacy NotesFeature-Policy renamed to Permissions-Policy: migration notes, old header syntax, and what still matters.