What Is the Same-Origin Policy? Web Security Basics
The same-origin policy stops a script from one site reading data loaded from another. How origins are compared, and how CORS and cookies fit in.
The same-origin policy (SOP) is the browser rule that stops a script running on one website from reading data belonging to another. It’s the single most important security boundary on the web — without it, any page you visit could read your bank’s session cookies, scrape your inbox from another open tab, or make authenticated requests to any site you’re logged into. Almost every other web security mechanism, including CORS and CSRF defenses, exists to carefully punch controlled holes in this default deny.
What counts as the same origin
An origin is the combination of scheme, host, and port. Two URLs are same-origin only if all three match exactly:
| URL | Same origin as https://example.com:443? |
|---|---|
https://example.com/page2 | Yes — same scheme, host, port |
http://example.com | No — different scheme |
https://api.example.com | No — different host (subdomain counts as different) |
https://example.com:8080 | No — different port |
https://EXAMPLE.com | Yes — host comparison is case-insensitive |
Note that a subdomain is a different origin from its parent domain. app.example.com and example.com cannot read each other’s data by default, even though they share a registered domain — this trips people up constantly when splitting a frontend and API across subdomains.
What the policy actually restricts
The same-origin policy doesn’t block all cross-origin activity — it blocks a script from reading the response of a cross-origin request, not necessarily from sending one. This distinction explains a lot of confusing behavior:
- Loading images, scripts, and stylesheets cross-origin is allowed.
<img src="https://other-site.com/logo.png">works fine — you can display the image, you just can’t read its raw pixel data via<canvas>without the server opting in via CORS headers. - Submitting a cross-origin form is allowed. This is exactly what makes CSRF attacks possible: the browser will happily submit a form to another origin, cookies and all, because the attacking page never needs to read the response.
fetch()andXMLHttpRequestto another origin are blocked from reading the response unless that origin explicitly opts in with CORS headers. The request may still reach the server and even execute — the browser just withholds the response from the calling script.- DOM access between cross-origin frames is blocked. A page can embed an
<iframe>from another origin, but JavaScript on the parent page cannot read or manipulate that iframe’s contents, and vice versa.
Why CORS exists
CORS is the mechanism that lets a server deliberately relax the same-origin policy for specific cross-origin callers, by returning headers like Access-Control-Allow-Origin. The browser enforces the policy; CORS is the server’s way of telling the browser “it’s fine to let this specific origin read my response.” Without a matching CORS header, the same-origin policy stays in force by default — this is why a frontend on one domain calling an API on another needs the API to explicitly allow it.
Cookies are a related but separate mechanism
Cookies aren’t scoped by the full origin — they’re scoped by domain (and optionally path), which is looser than the same-origin policy’s scheme+host+port rule. A cookie set for example.com is sent with requests to app.example.com and even over plain HTTP unless marked Secure. This looseness is exactly why CSRF attacks work: the browser attaches your session cookie to a cross-origin request automatically, since cookie scoping doesn’t know or care which page initiated the request. Modern browsers mitigate this with the SameSite cookie attribute, which restricts whether a cookie is sent on cross-site requests at all.
Related attacks the SOP prevents — and doesn’t
The same-origin policy is why XSS is dangerous in the first place: an XSS payload runs as the vulnerable site’s own origin, so it inherits full same-origin access to that site’s cookies, local storage, and DOM — the SOP doesn’t distinguish “legitimate site script” from “injected script,” only origins. It’s also why a content security policy is a useful layered defense: CSP restricts what an origin’s own scripts are allowed to load or execute, catching cases the same-origin policy alone doesn’t address. Separately, the SOP has nothing to do with network-layer interception — that’s what HTTPS and protections against a man-in-the-middle attack are for.
The takeaway
The same-origin policy is the browser’s default-deny rule for cross-origin data access, scoped by scheme, host, and port together. It quietly allows cross-origin requests to be sent — it just blocks scripts from reading the response — which is why CORS exists to opt back in, and why CSRF and cookie SameSite settings matter separately from SOP itself. Understanding where the policy’s boundary actually sits explains most of the “why won’t my fetch work” and “why is this a security bug” questions in web development.
Tagged
Keep reading
Chisato · · 5 min read IDS vs IPS: Intrusion Detection vs Prevention
An IDS watches network traffic and alerts on threats; an IPS sits inline and blocks them automatically. How the two compare and when to use each.
Chisato · · 4 min read What Is Clickjacking? UI Redress Attacks Explained
Clickjacking tricks a user into clicking something they can't see, hidden inside an invisible iframe. How the attack works and how to stop it.
Chisato · · 4 min read What Is Subresource Integrity (SRI)?
Subresource Integrity lets a browser verify a fetched script or stylesheet matches an expected hash, blocking a tampered CDN asset from running.