cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

The browser security model

Learn how origins, site isolation, timer limits, COOP and COEP, and V8 hardening keep browser scripts and data apart.

By the end, you can
  • 01
    Compare URLs accuratelyUse scheme, host, and port to explain same-origin decisions, then distinguish that from same-site.
  • 02
    Describe layered isolationConnect the same-origin policy, Chrome site isolation, timer precision, and engine hardening without treating any one layer as magic.
  • 03
    Ship isolation deliberatelyRecognize when COOP and COEP are needed, what they can unlock, and why feature detection remains necessary.

Security is several walls

A browser runs code from pages you did not build beside pages you did build. A shopping page, a bank, an ad, and an embedded video may all be open at once. The browser therefore uses several layers so code from one place cannot simply read the private data of another.

Definition

The browser security model is a set of boundaries. The same-origin policy limits direct web-page access, browser processes and sandboxes limit bug damage, and headers can request stronger isolation for selected APIs.

One layer does not replace the others. Origin checks decide whether script may directly inspect another origin's protected DOM or storage. Chrome Site Isolation adds a process boundary. Timer limits reduce a side channel. V8 adds engine hardening beneath the page level.

This follows Realms, globals & WindowProxy. A frame can have its own global object, but the browser still needs rules for what one frame may read from another. The next lesson, Load, link, evaluate, returns to module execution.

The same-origin policy

An origin is a URL's scheme, host, and port. The same-origin policy uses this tuple to restrict how a document or script from one origin interacts with protected resources from another origin. Paths do not change an origin.

Default ports and origin comparisonPop out in the code editor (opens in a new tab)JavaScript
const a = new URL("https://shop.example/cart");const b = new URL("https://shop.example:443/checkout");console.log(a.origin === b.origin); console.log(a.origin === new URL("http://shop.example").origin);console.log(a.origin === new URL("https://api.shop.example").origin);

Line 1 creates an HTTPS URL. Line 2 creates another HTTPS URL with port 443 written explicitly. Line 3 prints true because 443 is HTTPS's default port. Line 5 prints false because HTTP changes the scheme. Line 6 prints false because api.shop.example changes the host.

The policy is not “nothing crosses origins.” A page can often navigate, submit a form, or embed selected resources across origins. What it cannot normally do is read protected cross-origin responses, DOM content, or origin-keyed storage. A server can grant selected reads with CORS, while windows can exchange intentional messages with postMessage.

Real-life analogyFlats with separate locks

Imagine flats in an apartment building, each with its own lock. Your key opens your flat only. A different port or scheme is a different flat, even when the building name looks familiar.

In real life: Your key opens your flat
In JavaScript: A script reads its own origin's protected data
In real life: A different floor lock needs another key
In JavaScript: A different scheme is a different origin
In real life: A different flat number needs another key
In JavaScript: A different port is a different origin
In real life: A neighbouring flat has its own lock
In JavaScript: A different host is a different origin

Where the analogy stops: Real browser permission rules have carefully designed exceptions such as CORS and postMessage; a flat key is only a mental model.

Step through an origin comparison
Step 0 of 6Ready
Your turn: follow the blue line

Step through an instrumented URL comparison. This is a replay of the lesson model, not a browser security debugger.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const second = "https://shop.example:443/checkout"; function sameOrigin(first, second) {  const a = new URL(first);  const b = new URL(second);  return a.protocol === b.protocol &&    a.hostname === b.hostname &&    a.port === b.port;} console.log(sameOrigin(first, second));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Same origin and same site answer different questions

Same site is broader than same origin. Browser policies often use a scheme plus registered domain boundary, while direct script access uses the stricter scheme-host-port origin tuple. Two subdomains can be same-site while still being different origins.

Playground: edit the second URL
The same-origin modelPop out in the code editor (opens in a new tab)JavaScript
function sameOrigin(first, second) {  const a = new URL(first);  const b = new URL(second);  return a.protocol === b.protocol &&    a.hostname === b.hostname &&    a.port === b.port;} console.log(sameOrigin(  "https://shop.example/cart",  "https://shop.example:443/checkout",));
Live comparisondifferent origin
first tuplehttps | shop.example | 443

The fixed URL is `https://shop.example/cart`.

second tuplehttps | api.shop.example | 443

The editor input supplies this tuple.

same originfalse

All three origin parts must match.

simplified same sitetrue

This model compares scheme plus the final two host labels.

Try it yourself

Scheme: same; host: different; port: same. Same origin is false; simplified same site is true.

This runs the lesson's real URL models. The same-site result is simplified: real browsers use the Public Suffix List, not only two host labels.

Try the suggested URLs. The fixed first URL is https://shop.example/cart. Changing only the path keeps the origin. Changing to https://shop.example:443 keeps the normalized HTTPS port. Changing to HTTP or the API subdomain changes the origin.

A deliberately small same-site modelPop out in the code editor (opens in a new tab)JavaScript
function sameSite(first, second) {  const a = new URL(first);  const b = new URL(second);  const site = (url) => url.hostname.split(".").slice(-2).join(".");  return a.protocol === b.protocol && site(a) === site(b);} console.log(sameSite(  "https://shop.example/cart",  "https://api.shop.example/orders",));

Line 1 parses the first URL and line 2 parses the second. Line 3 keeps only the last two host labels, then line 4 also checks the scheme. It prints true for the shop and API examples. This is a teaching model only: real browsers use the Public Suffix List, so “last two labels” is not a production site algorithm.

Keep these browser terms separate
TermSmall ruleQuestion it answers
Same originSame scheme, host, and portCan this document directly read the other origin's protected data?
Same siteSame scheme and registered domainWhich site boundary may affect cookies and process placement?
Cross-origin isolatedCOOP plus COEP requirements are metCan this context use selected high-risk APIs with fewer restrictions?
Step through a same-site teaching model
Step 0 of 6Ready
Your turn: follow the blue line

Step through a deliberately simplified same-site comparison. It explains the shape of the rule, not the Public Suffix List algorithm.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const second = "https://api.shop.example/orders"; function sameSite(first, second) {  const a = new URL(first);  const b = new URL(second);  const site = (url) => url.hostname.split(".").slice(-2).join(".");  return a.protocol === b.protocol && site(a) === site(b);} console.log(sameSite(first, second));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Process-per-site and site isolation

The same-origin policy is a rule enforced in browser code. Browser vendors also use architecture to reduce the damage when a rule has a bug. In Chrome, Site Isolation places pages from different sites into different sandboxed renderer processes as an extra defense.

A model of two cross-site pagesPop out in the code editor (opens in a new tab)JavaScript
const page = "https://shop.example";const frame = "https://news.example"; console.log("same site?", sameSite(page, frame));console.log("same origin?", sameOrigin(page, frame));console.log("Chrome isolates cross-site pages in separate renderer processes");

Lines 1 and 2 name pages on two different sites. Lines 4 and 5 would both print false with the lesson models. Line 6 describes the Chrome-specific result: cross-site documents are placed in separate renderer processes, so one site's memory is not in another site's renderer process.

Chrome defines a site roughly as scheme plus registered domain, ignoring subdomains and ports for this process boundary. That is intentionally different from origin. It preserves web compatibility while still placing cross-site documents apart. The companion lesson Browser architecture explains browser, renderer, and sandbox roles in more depth.

Defense in depth

Site Isolation does not make the same-origin policy unnecessary. It is an additional layer: if malicious code or a renderer bug defeats one check, keeping another site's sensitive data out of the process makes theft harder.

Spectre and timer precision

Spectre is a family of CPU side-channel attacks. In plain words, careful timing can sometimes reveal information indirectly, rather than an ordinary JavaScript property access returning a secret. Browsers reduce that risk with several defenses, including isolation and less precise clocks in ordinary contexts.

The documented timer resolutions in millisecondsPop out in the code editor (opens in a new tab)JavaScript
const isolatedResolution = 0.005;const regularResolution = 0.1; console.log("isolated context microseconds:", isolatedResolution * 1000);console.log("regular context microseconds:", regularResolution * 1000);

Line 1 stores 0.005 milliseconds and line 2 stores 0.1 milliseconds. Lines 4 and 5 multiply by 1,000, so the snippet prints 5 and 100. MDN documents these as isolated and non-isolated timer resolutions. Say “in Chrome” when discussing the well-known 5-microsecond and 100-microsecond behavior, because browsers can vary their mitigations.

Real-life analogyTiny sounds through a wall

People found that by carefully timing tiny sounds through a wall, they could guess a neighbour's secrets. The building made its clocks less precise and put sensitive neighbours in separate buildings. Those are the two ideas: coarser timers and site isolation.

In real life: Someone listens for tiny sounds
In JavaScript: An attacker measures tiny timing differences
In real life: The clock has fewer markings
In JavaScript: The browser coarsens timer precision
In real life: Sensitive neighbours use separate buildings
In JavaScript: Site isolation separates cross-site renderers

Where the analogy stops: Spectre involves CPU speculation and cache effects, not literal sounds or walls. The analogy only explains why timing detail and separation both matter.

This is why a page should not assume performance.now() has one universal precision. Measure performance for product work, but do not build a security design that depends on counting microscopic time differences.

COOP, COEP, and cross-origin isolation

Cross-origin isolation is an opt-in browser state for a document and its browsing context group. It allows selected powerful APIs with fewer restrictions, while demanding stronger agreement about popups and embedded cross-origin resources.

The two response headersHTTP
// HTTP response headers, set by the server.Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp // Cross-origin resources must opt in with CORP or CORS.

Line 2 is COOP: same-origin keeps the document's browsing context group for compatible same-origin documents. Line 3 is COEP: require-corp blocks no-CORS cross-origin resources unless they explicitly allow embedding with CORP, or are loaded with CORS permission.

When the requirements are satisfied and Permissions Policy does not block it, crossOriginIsolated becomes true. That can unlock SharedArrayBuffer, more precise timers, and performance.measureUserAgentSpecificMemory(). These are capabilities to feature-detect, not promises that every browser offers every API.

Feature-detect the current isolation statePop out in the code editor (opens in a new tab)JavaScript
const isolated = globalThis.crossOriginIsolated === true;console.log("cross-origin isolated:", isolated); if (isolated && "SharedArrayBuffer" in globalThis) {  console.log("shared memory is available");} else {  console.log("use an ordinary ArrayBuffer here");}

Line 1 converts the current environment into a boolean. Line 2 prints that boolean. The normal page path prints cross-origin isolated: false and then use an ordinary ArrayBuffer here. An isolated page with shared memory support prints the other message instead.

Adopting COEP can break third-party images, scripts, fonts, or iframes that did not opt in. Start with report-only tooling, inventory embedded resources, and ask each resource for CORS or CORP support. The published CORS and Windows and frames lessons provide the related page-level tools.

The V8 sandbox and JIT hardening

The V8 sandbox is an in-process security boundary in V8. Its basic aim is to keep V8 heap memory in a bounded region, so a memory-corruption bug in V8 has a harder time reaching the rest of the browser process. This is engine work beneath your page; JavaScript cannot turn it on with a header.

A short model of engine defensesJavaScript
// This is a conceptual summary, not runnable V8 source.const protections = [  "V8 heap stays inside a bounded sandbox region",  "outside pointers use checked indirection",  "JIT code pages are not writable and executable together",]; console.log(protections.length);

Line 2 describes the heap boundary. Line 3 summarizes the checked indirection used for values that refer outside the sandbox. Line 4 names a separate JIT hardening rule: generated code pages are not writable and executable at the same time. Line 8 would print 3, but the code is a summary, not the V8 implementation.

JIT means just-in-time compilation: an engine can turn hot JavaScript into machine code while a program runs. Hardening makes it harder for a memory bug to rewrite executable code. The V8 sandbox is also not a cure for every V8 bug; it aims to contain the impact so escaping the heap needs another boundary failure.

Keep the layers honest

Origin policy protects web content from other origins. Site Isolation separates browser renderer processes in Chrome. The V8 sandbox contains V8 heap corruption inside a process. They overlap in purpose but operate at different levels.

Practical website decisions

Most application teams work directly with origins, CORS, frame messaging, and headers. They benefit from knowing the lower layers because a security report may mention a renderer process, a timer, or cross-origin isolation. But the first fix should match the actual boundary that is missing.

  • Choose a separate origin for an application that needs a real security boundary, not just a separate route.
  • Use postMessage with a specific target origin for intentional frame or popup communication.
  • Use CORS only for servers that truly intend to share a response with another origin.
  • Before enabling COEP, inventory cross-origin images, fonts, scripts, iframes, and workers.
  • Feature-detect crossOriginIsolated and related APIs instead of assuming a browser state.
Which boundary is this?
  • https://shop.example:8443 differs from https://shop.example.
  • shop.example and api.shop.example need a DOM access check.
  • Chrome separates cross-site documents into renderer processes.
  • A browser makes fine timing observations harder to use as a side channel.
  • Cross-Origin-Opener-Policy: same-origin on a top-level response.
  • Cross-Origin-Embedder-Policy: require-corp on a response.
Try it yourself
0 of 6 correct

Sort each card by the browser rule it most directly describes. The explanations connect the layers without pretending they are interchangeable.

Choose a category for every card. You can change an answer at any time; Reset clears them all.
A practical map of the protection layers
LayerWhat it limitsDeveloper action
Same-origin policyRestricts direct access to another origin's DOM, storage, and many reads.Use CORS or postMessage for intended cross-origin cooperation.
Chrome site isolationPlaces cross-site documents in different sandboxed renderer processes.This is Chrome-specific defense in depth, not a JavaScript API.
Timer precision limitsMakes some timing observations less precise to reduce side-channel detail.Do not treat one observed timer difference as a security promise.
COOP and COEPOpt a page into a cross-origin isolated browsing context group when requirements are met.Resources need CORP or CORS consent under require-corp.
V8 sandbox and JIT hardeningLimits damage if a V8 memory bug corrupts heap data and protects generated code pages.These are engine defenses, not page-controlled headers.

Common security-model misconceptions

  • “Same site means scripts can read each other.” No. Direct protected access normally needs same origin.
  • “CORS disables the same-origin policy.” No. It is a server-controlled exception for selected cross-origin reads.
  • “COOP and COEP are JavaScript settings.” No. They are HTTP response headers sent before page JavaScript runs.
  • “Site Isolation is a universal browser-process guarantee.” It is a Chrome security feature with platform and compatibility details.
  • “A V8 sandbox means page bugs cannot matter.” It is one defense layer; secure page code and server checks still matter.
Security terms that sound alike
TermWhat it meansDo not confuse it with
Same siteA broader grouping used by browser policies.Same origin; subdomains and ports can differ while a site relation remains.
CORSA server permission mechanism for selected cross-origin reads.A way to turn two origins into the same origin.
Site isolationChrome renderer-process separation for different sites.A guarantee that every URL always receives a unique process in every browser.
crossOriginIsolatedA boolean state you feature-detect in the current context.A header that JavaScript can set after the page has loaded.

The useful habit is to ask two questions: what is the attacker trying to read or control, and which layer actually owns that boundary? That keeps a header fix, a CORS fix, and a process-isolation explanation from being mixed together.

Practice exercises

Exercise 1 · Warm-upPredict a default-port comparison

Read the code and type the boolean it prints.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const a = new URL("https://shop.example/cart");
const b = new URL("https://shop.example:443/checkout");
console.log(a.origin === b.origin);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upSpot the scheme difference

    What does the comparison print?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const secure = new URL("https://shop.example");
    const plain = new URL("http://shop.example");
    console.log(secure.origin === plain.origin);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeName the changed origin part

      Which part of the origin tuple differs?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const shop = new URL("https://shop.example");
      const api = new URL("https://api.shop.example");
      console.log(shop.origin, api.origin);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeChoose the isolation headers

        Your app needs a cross-origin isolated context for shared memory. Name the two usual response headers.

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeFeature-detect the page state

          What should real application code check before using an isolated-only capability?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const isolated = false;
          console.log(isolated ? "use SharedArrayBuffer" : "use ArrayBuffer");

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeApply COEP to a real website

            A product page uses third-party images and scripts. What should the team test before enforcing COEP?

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              Use the URL tuple for origin questions, then name the independent layer that handles processes, timers, response headers, or V8 heap corruption.

              Browser security model quiz · 7 questionsScore: first tries count
              1. Question 1 of 7What makes two ordinary web URLs the same origin?

                Choose an answer to see the explanation.

              2. Question 2 of 7What does this print?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                const a = new URL("https://shop.example");
                const b = new URL("https://shop.example:443");
                console.log(a.origin === b.origin);

                Choose an answer to see the explanation.

              3. Question 3 of 7What does Chrome Site Isolation add beyond the same-origin policy?

                Choose an answer to see the explanation.

              4. Question 4 of 7Why do browsers reduce timer precision in ordinary contexts?

                Choose an answer to see the explanation.

              5. Question 5 of 7Which pair is commonly used to opt into cross-origin isolation?

                Choose an answer to see the explanation.

              6. Question 6 of 7What does crossOriginIsolated tell a page?

                Choose an answer to see the explanation.

              7. Question 7 of 7What is the V8 sandbox trying to contain?

                Choose an answer to see the explanation.

              Key takeaways

              • Same origin means the same scheme, host, and port; a path does not change an origin.
              • Same site is broader and must not be confused with permission for direct script access.
              • Chrome Site Isolation uses separate sandboxed renderer processes for different sites as defense in depth.
              • Timer coarsening and isolation help reduce Spectre-style side-channel risk.
              • COOP and COEP can opt a page into cross-origin isolation, which you should feature-detect with crossOriginIsolated.
              • The V8 sandbox and JIT hardening protect a lower engine layer; they complement, not replace, origin policy.

              Remember the one-liner.
              Browser security works because several independent boundaries keep one page's code and data from quietly becoming another page's problem.

              Coming next: Load, link, evaluate. You will follow a module graph through the browser's three module phases.

              CompleteFrontend Clear concepts. Working examples.