ESC

Type to search the knowledge base.

Same-Origin Policy

Origin tuple (scheme/host/port), what SOP blocks, and how CORS, postMessage, and cookies relate.

intermediate3 min read
  • 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.

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

Related guides