Module VII · Running

The security model

Module 6 left a thread that runs every script with equal authority and no notion of trust — your code, the third-party CDN script from Module 4, and code that means you harm, all on the same loop with the same reach into the same page. Something has to decide who may do what. That something is the security model, and it is the browser at its most operating-system-like: an access-control system separating mutually distrustful code, running on a machine where the code arrives unbidden from strangers. This is the module where Demo Company's threat pages stop being curiosities and become the syllabus.

7.1 The origin is the unit of trust

The browser's entire security model is built on one identifier: the origin, the triple of scheme, host, and port. Module 1 called the origin the platform's process and permission boundary; this module is what that boundary actually does. Two pieces of content share trust if and only if they share an origin. Same origin means full mutual access; different origin means walls, by default. Everything else — the same-origin policy, CORS, cookie scoping, storage partitioning — is elaboration on that one line.

The same-origin policyFor the reference origin https on www.democompany.com port 443, a URL with a different path is same-origin, but a different scheme, a different host, or a different port each make it cross-origin. All three of scheme, host, and port must match.Reference origin — scheme, host, and port must ALL match:https://www.democompany.com:443https://www.democompany.com/aboutsame — only the path differshttp://www.democompany.com/cross — scheme differshttps://api.democompany.com/cross — host differshttps://www.democompany.com:8443/cross — port differs
Figure 7.1 — The same-origin policy. A different path is still the same origin; a different scheme, host, or port is not. https and http are different origins, which is one more reason the modern web is HTTPS-only.

7.2 What the policy actually restricts

The same-origin policy is precise about what it stops, and the precision is where the danger and the defenses both live. It restricts reading across origins, not sending and not embedding. A page may freely send a request to another origin and freely embed another origin's resources — but it may not read the response or inspect the embedded content. That asymmetry is the most important table in web security.

Cross-origin capability matrixA fetch can send a cross-origin request but cannot read the response unless CORS allows it. An image, iframe, or font can be embedded but not inspected. A script loaded with a src attribute is both loaded and run inside your origin, giving it full access to your page.Send / LoadRead / Inspectfetch / XHR✓ send request✗ read response — unless CORS allows itimg / iframe / font✓ embed / display✗ inspect pixels or DOM<script src>✓ load + runruns IN your origin → FULL ACCESScross-origin content can be sent-to and embedded, but not read — except a script you embed, which runs as you
Figure 7.2 — The asymmetry. The browser blocks cross-origin reads to protect your data sitting on other origins. The glaring exception is the bottom row: a script you load with src does not stay at arm's length — it executes inside your origin with every power your own code has. That is the Module 4 CDN line, and it is why third parties are a trust decision, not a convenience.
The web lets you embed anything and read almost nothing — but a script you embed becomes you. Choosing what to embed is choosing whom to trust completely.

7.3 CORS: the controlled exception

Plenty of legitimate work needs to read across origins — a front end on one origin calling an API on another. Cross-Origin Resource Sharing is the opt-in that allows it. The server that owns the data chooses to return an Access-Control-Allow-Origin header naming who may read its responses; for anything beyond simple requests, the browser first sends a preflight OPTIONS request to ask permission before sending the real one. The key insight, and a common misunderstanding: CORS does not protect the server — the server can always be reached. It protects the user's data on other origins by default-denying the read, and lets the data's owner grant exceptions. CORS is the browser enforcing one server's policy on behalf of a user talking to another.

7.4 Cookies and credentials

A cookie set by an origin is attached automatically to future requests to that origin — the mechanism that makes you stay logged in (Module 2's Cookie header). That automatic attachment is powerful and dangerous, so cookies carry flags that are pure security controls: HttpOnly hides the cookie from JavaScript entirely, so that even a script running in your origin cannot read your session token; Secure sends it only over HTTPS; SameSite controls whether it rides along on requests triggered by other sites, the central defense against request forgery. Third-party cookies — set by an origin embedded across many sites — are the classic cross-site tracking mechanism, and their long deprecation is one of the platform's biggest privacy shifts.

7.5 The attacks the architecture permits

Three classic attack classes follow directly from the model above. We describe them as a defender must understand them — what they are and why the architecture allows them — not as recipes.

Cross-site scripting (XSS) is the bottom row of Figure 7.2 turned against you. If an attacker can get their script to run in your origin — by smuggling it through unsanitized user input that your page reflects back as markup — that script has the full access any in-origin code has: it can read the DOM, read non-HttpOnly cookies, and make same-origin requests as the user. The injected script is trusted not because it is trustworthy but because it is in the origin. This is why HttpOnly on a session cookie matters so much: it removes the session token from what an injected script can reach.

Cross-site request forgery (CSRF) weaponizes the send-but-not-read half of the asymmetry. A page cannot read another origin's response, but it can send a request — and the browser will attach that origin's cookies. So a malicious page can cause the user's browser to fire a state-changing request to a site they are logged into, riding their session, even though the attacker never sees the reply. The defense is SameSite cookies, which withhold the credential from cross-site requests, plus anti-forgery tokens the attacker cannot guess.

Clickjacking abuses cross-origin embedding: an attacker frames your real site invisibly over their own bait, so the user's click lands on your page without their knowledge. The defense is telling the browser who may frame you — the frame-ancestors directive of Content-Security-Policy, historically X-Frame-Options.

7.6 Defense in depth

No single mechanism secures a page; the web's security is a stack, each layer assuming the others might fail. The author opts into most of it through HTTP response headers and element attributes — the browser enforces what the server declares.

Defense in depth on the webFive layers, each stopping a different attack: TLS stops eavesdropping in transit; the same-origin policy and CORS stop cross-origin data theft; CSP and Subresource Integrity stop injected or tampered code; HttpOnly and SameSite cookies stop cookie theft and request forgery; the sandbox and Site Isolation stop a compromised page from reaching other sites.TLS / HTTPSstops eavesdropping & tampering in transitSame-origin policy + CORSstops cross-origin data theftCSP + Subresource Integritystops injected or tampered code from runningHttpOnly + SameSite cookiesstops cookie theft & request forgerySandbox + Site Isolationstops a compromised page reaching other sites
Figure 7.3 — The stack. Content-Security-Policy restricts where scripts and other resources may load from and can forbid inline script; Subresource Integrity rejects a CDN file whose hash has changed; the cookie flags protect credentials; and beneath it all, the sandbox and Site Isolation of Module 1 contain a breach to a single site. Assume each layer can fail, and the next still holds.

7.7 The lab: Demo Company's threat arc

The threat pages now read as a single argument. Walk them with the Network and Console panels open:

javascript.html third-party CDN script runs in your origin: supply-chain trust (use SRI + CSP) resources.html cross-origin image embeds fine; pixels not readable (canvas taint) resources-keylog.html tracking script in-origin, so it CAN read your input; SOP won't help resources-hacked.html malicious script the XSS endpoint: in-origin code with full access

The throughline: every one of these arrives via the same ordinary <script> or resource reference from Module 4, and the event loop of Module 6 runs each with identical authority. The same-origin policy guards the boundary between origins, but does nothing about hostile code you invited inside yours. The real defenses are upstream: do not load code you do not trust; constrain what can load with CSP and SRI; and keep the secrets that matter (HttpOnly session tokens) out of JavaScript's reach entirely, so that even a breach inside the origin cannot take them.

7.8 What you now have

The model whole: the origin as the unit of trust; the same-origin policy restricting cross-origin reads while permitting sends and embeds; the dangerous exception that an embedded script runs inside your origin with full power; CORS as the owner's opt-in to cross-origin reads; cookies and their security flags; the three attack classes the architecture permits — XSS, CSRF, clickjacking — and why each follows from the model; and defense in depth, the stack of TLS, SOP and CORS, CSP and SRI, cookie flags, and the sandbox and Site Isolation from Module 1. The unifying idea: the event loop runs every script equally, so a separate subsystem must decide what equal access to the thread is allowed to reach — and that subsystem is keyed entirely on the origin.

The origin turns out to scope more than scripts and requests. The data a page stores — cookies, but also Web Storage, IndexedDB, the cache — is partitioned by origin too, so the security boundary extends into persistence. Module 8 is the browser as a filesystem: what a page can keep, where, for how long, and under whose isolation — plus the service worker, a programmable proxy that sits between the page and the network, and the hardest naming problem in computing.

The same-origin policy guards the door between origins. It cannot help with the code you carried inside. Security is mostly about what you choose to let in.