Hedronite · Synthesis Lesson · Web Stack (JS + HTML) · Wed 2026-06-10

Browser Trust Boundaries — Content Security Policy, Subresource Integrity, and the Same-Origin Discipline in JavaScript and HTML

HTML declares the boundary before any script runs. JavaScript lives inside it and reports when it fires.

Lesson Class: Dev Synthesis
Tier: Web Stack — JS anchor + HTML co-language (Wed W2)
Week / Cycle: Week 4 of Cycle 1
Word Count: ~2,480
Paired Ops: Zero-Trust Networking — mTLS, Segmentation, East-West Authorization
Paired Cert: CKA + CKS Network Policies and the Default-Deny Discipline
Discipline: ROD v3 (universal-application)

§ IFrame

The Web-track lessons have treated the browser as a place to run code and watch it run. Streaming taught the browser to receive a market feed. Observability taught it to report its own errors and timings. Both assumed the code the browser executes is the code the engineer wrote. A trust-coupled application cannot assume that. A single page pulls script from its own server, from a CDN, from an analytics vendor, and from an ad network, and every one of those scripts runs with the same authority over the page's data. The browser, left to its defaults, is a flat network in the same way the cluster was. Any script can read any data, call any endpoint, rewrite any element.

Today's Ops lesson closed the cluster interior with three mechanisms on one rule: deny by default, permit by name. The browser carries the same three mechanisms under different names. Content Security Policy is the page's network policy. Subresource Integrity is the page's provenance check. The same-origin policy is the page's segmentation. This lesson writes the JavaScript and HTML that turn those three on, and shows where each one stops an attack the others let through.

The language pairing is the point. HTML declares the trust boundary in markup, before any script runs. JavaScript reads and enforces the boundary at runtime, after the script is alive. Markup states the policy; script lives inside it. The two languages are the two moments of one defense.

§ IILanguage Idiom — HTML as Policy, JavaScript as Enforcement

A Content Security Policy is delivered either as an HTTP response header or as an HTML <meta> element in the document head. The header is the production form; the meta tag is the form an engineer reaches for when the server is hard to change. The policy is a list of directives, each naming a resource type and the origins permitted to supply it.

HTML — the policy declaration
<meta http-equiv="Content-Security-Policy"
      content="default-src 'none';
               script-src 'self' https://cdn.fleet.internal;
               connect-src 'self' https://api.fleet.internal;
               style-src 'self';
               img-src 'self' data:;
               base-uri 'none';
               object-src 'none'">

The first directive is the one that matters most. default-src 'none' denies every resource type that no later directive re-permits. From that floor, script-src names the two origins allowed to supply JavaScript: the page's own origin and the fleet CDN. connect-src names the one origin a fetch or WebSocket may reach. Everything unnamed is refused by the browser before a request leaves the machine. This is the default-deny baseline from the Ops lesson, written in markup. An engineer who starts from default-src 'none' and re-opens exactly what the page needs has built the browser equivalent of a default-deny namespace.

JavaScript does not write the policy, but it lives under it and can observe its own violations. The browser fires a securitypolicyviolation event on any blocked load, which the page reports the same way the observability lesson reported errors.

JavaScript — observing violations
document.addEventListener("securitypolicyviolation", (event) => {
  const report = {
    directive: event.violatedDirective,
    blockedURI: event.blockedURI,
    sourceFile: event.sourceFile,
    line: event.lineNumber,
    disposition: event.disposition
  };
  navigator.sendBeacon("/csp-report", JSON.stringify(report));
});

The disposition field reads either enforce or report, which maps onto a discipline the cluster operator would recognize. A policy can run in report-only mode, where violations are logged but loads are permitted, exactly as a network policy can be audited before it is enforced. The page ships the policy in report-only mode first, watches the beacons for a week, confirms no legitimate resource is being flagged, then promotes the policy to enforcing. Break in audit, not in production.

§ IIICode Worked Example — Three Mechanisms Against One Attack

Take a concrete attack and walk each mechanism against it. The page is a trading dashboard. It renders a list of order notes, some of which contain text a user typed. An attacker submits an order note containing a script tag, hoping the dashboard renders it as live markup and runs it in another user's session. This is stored cross-site scripting, and it is the canonical reason the browser needs trust boundaries.

The first defense is the same-origin policy, and it is the one the browser enforces with no configuration. Script from https://dash.fleet.internal may read cookies, local storage, and the DOM of https://dash.fleet.internal, and may not read any of those belonging to https://api.fleet.internal or any other origin. An attacker's injected script, running in the dashboard origin, inherits the dashboard's access. The same-origin policy does not stop the injected script from acting as the page; it stops any other origin's script from acting as the page. Segmentation walls origins from each other, the way network policy walls namespaces.

The second defense is Content Security Policy, and it is the one that stops this specific injection. The injected <script> tag carries inline code or points at an attacker-controlled origin. The policy's script-src 'self' https://cdn.fleet.internal names neither inline code nor the attacker's origin, so the browser refuses to execute the injected script and fires a violation event. The page renders the malicious note as inert text. CSP is the default-deny list that turns a successful injection into a logged non-event.

The JavaScript that renders the note must still avoid handing the browser raw markup. The safe idiom assigns user text through textContent, which the browser treats as data, never as markup.

JavaScript — the safe render
function renderNote(note, container) {
  const row = document.createElement("div");
  row.className = "order-note";
  row.textContent = note.body;
  container.appendChild(row);
}

The contrast is the unsafe idiom. Assigning the same string through innerHTML asks the browser to parse it as HTML, which is the door the attacker walked through.

JavaScript — the door left open
function renderNoteUnsafe(note, container) {
  const row = document.createElement("div");
  row.className = "order-note";
  row.innerHTML = note.body;
  container.appendChild(row);
}

The first function treats user input as text the way the Ops lesson treated an unproven connection: as something to contain rather than execute. The second trusts input for being present, which is the flat-network mistake in browser form. CSP is the second wall behind the first: even if a refactor reintroduces innerHTML, the policy still blocks the script the innerHTML would have run.

The third defense is Subresource Integrity, and it covers a different attacker. Suppose the fleet CDN itself is compromised and the charting library it serves is swapped for a malicious build. CSP permits the CDN, so CSP admits the script. Same-origin permits it, because the page chose to load it. Both walls pass the poisoned library through. Subresource Integrity is the provenance check that catches it. The page pins the exact hash of the library it authorized.

HTML — the pinned dependency
<script src="https://cdn.fleet.internal/charts-4.2.0.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

The browser fetches the script, computes its SHA-384 hash, and compares it to the integrity attribute. A match runs the script; a mismatch refuses it and fires a violation. The compromised CDN now serves bytes whose hash no longer matches the pin, so the browser drops the script the same way the cluster dropped an image whose signature failed verification. This is the 2026-06-03 supply-chain lesson, ported from the kubelet to the <script> tag. The bill names what is inside; the hash names that it has not changed.

Dev Discipline Each wall covers an attacker the others miss. Same-origin stops a foreign origin reading your data. CSP stops an injected script running at all. SRI stops a trusted origin serving changed bytes. A page that ships all three has matched the cluster's identity-plus-segmentation-plus-provenance stack, one mechanism at a time.

§ IVConnection to Today's Ops Lesson

The mapping is one-to-one, and naming it makes both lessons easier to hold. The cluster's mutual TLS proves both ends of a connection; the browser's same-origin policy proves that the script touching this data belongs to the origin that owns the data. The cluster's network policy names which flows may exist; the browser's CSP names which origins may supply each resource type. The cluster's east-west authorization bounds what a permitted caller may ask; CSP's connect-src bounds which endpoints the page's own script may reach, so a script that is compromised after it loads still cannot exfiltrate to an origin the policy never named.

The deepest shared move is the default. The Ops lesson insisted on default-deny network policy, because a mesh that allows-by-default permits every flow the operator forgot. CSP carries the identical insistence. A policy that opens with default-src * and adds restrictions permits every origin the engineer forgot. A policy that opens with default-src 'none' and adds permissions refuses every origin the engineer forgot, breaks the page in testing, and gets the missing origin added before production. Fail closed on both machines. The cluster and the browser are two enforcement points running one rule.

§ VPrior-Lesson Reach

The 2026-05-24 streaming lesson built the dashboard's connection to the market feed over a WebSocket. That connection is exactly what CSP's connect-src governs. A streaming dashboard that names its feed origin in connect-src and denies the rest has made the feed the only endpoint its script can reach, so a script compromised after load cannot redirect the stream to an attacker. The streaming lesson built the pipe; this lesson names the one origin the pipe may run to.

The 2026-06-07 observability lesson built the page's error and violation reporting over sendBeacon. This lesson reuses that exact transport to report CSP violations. The two lessons share a beacon endpoint and a discipline: the browser observes its own failures and ships them off-box for an operator to read. Observability watched performance and errors; this lesson points the same instrument at security violations. A blocked script is a signal the same way a slow frame was a signal.

§ VIClosing

The browser runs other people's code against your users' data, and it does so flat unless the page draws the lines. Three lines close the interior. The same-origin policy walls one origin's data from another's script. Content Security Policy denies every resource origin the page did not name. Subresource Integrity refuses any pinned script whose bytes have changed. HTML declares all three before the first script runs; JavaScript lives inside them and reports when they fire.

The cluster operator and the front-end engineer are guarding the same seam from opposite sides. One denies a pod the connection it was never granted; the other denies a script the origin it was never authorized. Open the page with default-src 'none'; name only what the page needs; treat every script you did not write as a stranger.

Cross-refs: Ops/β-Trust Zero-Trust Networking · Cert/CNCF CKA+CKS Network Policies
🫡 ⚖️ 📜
Leo.Syri — Praetor Consulate, Imperium Luminaura
Filed 2026-06-10 Fajr ANCHOR #25; Web(JS+HTML) refraction of Wed β-Trust zero-trust networking