BUIzz's Policy Invariant: What the Browser Must Preserve

BUIzz is easier to understand once its target is stated as an invariant: a browser should not weaken a site's security policy merely because a user reaches content through a different browser-owned path. This chapter defines what that policy state contains, how the main policy families constrain different browser actions, and why Content Security Policy (CSP) inheritance makes the problem especially visible. The goal is to distinguish a genuine loss of protection from any superficial difference between two page visits.

A policy begins as data, then becomes browser state

A security header is a message in an HTTP response, not a small security program that runs by itself. The ordinary sequence has three parts. A browser requests a page. The web server or application returns the page together with headers that describe restrictions. The browser then interprets those headers and enforces them while it loads resources, executes code, creates browsing contexts, sends requests, and renders the result.

The third step belongs to the browser. A website can declare that scripts should come only from trusted sources, that a cookie should not accompany a cross-site request, or that a connection should be upgraded to HTTPS. The site cannot directly implement every enforcement step. It depends on the browser to carry the declaration into the operations that follow. That dependency is why BUIzz treats the browser implementation—not just the page configuration—as the object under test.

The browser does not hold one undifferentiated “security setting.” Each policy describes a different kind of protected behavior. CSP controls whether resources can be requested, embedded, or executed, and its sandbox directive can restrict actions such as script execution, downloads, form submission, and popup creation. SameSite cookie attributes constrain when cookies are sent in cross-site contexts. Permissions Policy controls which origins may use sensitive capabilities such as the camera, microphone, or geolocation. Cross-Origin-Opener-Policy, or COOP, controls whether a page keeps an opener relationship with a page from another origin. HTTP Strict Transport Security, or HSTS, requires later connections to use HTTPS. Framing controls and Referrer-Policy constrain whether a page can be embedded and what referrer information a request exposes.

These policies differ in both their protected object and their failure signal. A CSP problem may be visible because a script runs when it should be blocked. A SameSite problem appears in a request's Cookie header. A Permissions Policy problem can appear when a script reaches a feature that the policy denies. A COOP problem can be inferred from an unexpected window.opener. An HSTS problem is visible in the URL scheme used for a connection. Framing and referrer policies require still other observations. The policy declaration is the starting point; the protected browser behavior is the thing that must remain correct.

CSP Level 3 makes this lifecycle more explicit. The W3C document describes a policy as a set of directives applied to a document, worker, or worklet. It distinguishes policies that enforce restrictions from policies that only report violations, and it recognizes policies delivered through a response header or a meta element. A response's Content-Security-Policy header is parsed into a policy list associated with the response's origin. Directives can participate in several kinds of checks, including checks before a request, after a response, for inline behavior, during initialization, before navigation, and while processing a navigation response.

This vocabulary matters because “the page has CSP” does not identify a single moment. The browser may be deciding whether a script is allowed, whether a resource can be fetched, whether a navigation is permitted, or how a new document should be initialized. A BUI action can change which document or browsing context is being created without changing the original response header. The security question is therefore about the policy's life after installation: which state crosses the transition, and which state is re-created at the destination?

The same distinction explains why BUIzz separates security bugs from functional bugs. A pre-interaction and post-interaction visit may differ for a legitimate reason. For example, a top-level navigation and an iframe navigation do not necessarily receive the same SameSite=Lax cookie treatment. If a test sees a difference, that difference is a signal to interpret, not proof that the browser is less secure. BUIzz classifies a finding as a security bug when the interaction makes enforcement less restrictive than intended. It classifies a functional bug when the interaction makes enforcement stricter than intended. The direction of the change and the governing specification both matter.

There is also a useful limit on what a policy promises. The W3C description presents CSP as defense in depth. It can reduce the harm that content injection causes, but it is not a substitute for careful input validation and output encoding. That statement does not weaken BUIzz's question. It gives the question the right scope: if a website uses CSP as one layer of defense, does the browser honor that layer consistently along the paths that users can take?

CSP makes continuity visible

CSP's local-scheme rules provide a precise example of a policy that must travel with a browser context. A page may create or open content using mechanisms such as srcdoc, blob:, data:, or certain about:blank documents. Some of these destinations can contain content controlled by the source page. If the destination were treated as a completely fresh, unprotected environment, the page could use that environment to escape restrictions that apply to the parent.

The current W3C CSP Level 3 text therefore says that documents loaded from local schemes inherit a copy of the source document's policies. Its rationale is direct: without inheritance, a page could embed a srcdoc document containing inline script and execute that script even when the parent policy does not allow unsafe-inline. The copied policy is a snapshot made when the new document is created. Later changes to the new document's policy list do not change the source document's list, and changes to the source do not retroactively alter the copy.

That rule does not mean that a parent page's policy is copied into every document it ever encounters. It applies to the local-scheme cases and the relationships defined by the relevant platform rules. The important point is that the browser must preserve the security relationship when it creates a destination whose content is still under the source page's control or is otherwise covered by the inheritance rule. The destination's URL scheme and browsing-context relationship are part of the enforcement decision.

This makes a navigation a sequence of security decisions rather than one event. The browser has to identify the source document, create or select the destination browsing context, determine the destination's scheme and origin behavior, establish the policy list for the new document, and then run the checks appropriate to the request or resource. A failure at any one of those boundaries can look like a problem with the final page even though the original response was correct. For a tester, the sequence supplies useful control points: compare the policy-bearing initial document, the transition that created the destination, and the first security-relevant action in that destination.

The copy semantics also explain why policy continuity is not the same as copying a string into a new response. The W3C description treats the inherited CSP list as a snapshot at document creation. The destination has its own policy state after the copy is made, while the source retains its own state. That prevents a later change in one document from silently rewriting the other. It also means that a browser implementation must get the timing right. If it creates the new document without the inherited state, applies the state only after an inline script has already run, or drops it during a UI-specific reconstruction, the restriction has failed even if a later inspection appears to show a policy somewhere in the browsing context.

A simple example makes the distinction concrete. A page with script-src 'nonce-123' authorizes a script carrying that nonce; it does not authorize every script that happens to be created later. If the page constructs a blob: document containing an unauthorized script, the browser must establish the related document with the applicable inherited restriction before that script can execute. The relevant question is not whether the new document has a visible copy of the header as text. It is whether the browser's script check sees the policy at the moment it decides whether the code may run.

This timing perspective also explains why a policy-specific observation is valuable. Looking only at the address bar or at a page's markup could miss a transient enforcement gap. BUIzz instead observes the protected action: whether code executes, whether a cookie is attached, whether a feature request succeeds, or whether an opener relationship exists. Those outcomes reveal what the browser actually allowed after the transition. They do not by themselves identify the implementation line responsible, but they tell the tester that the policy state at the boundary deserves investigation.

Suppose a page receives a policy such as script-src 'nonce-123'. The nonce identifies a script that the policy author has authorized; an inline script without that authorization should not run. If a link on that page constructs a blob: document containing an unauthorized script, the browser must not turn the local-scheme navigation into a way around the parent policy. The protected state is not merely the text of the header sitting in the first response. It is the restriction on script execution as the browser creates and initializes the related document.

The same reasoning explains the motivating Chrome case in the BUIzz study. On the initial visit, the nonce-protected test code behaves as expected and the nonce-less code remains blocked. When a link is dragged to the address bar, the browser takes a different navigation path. The study reports that the parent CSP is not inherited in the resulting case, allowing the nonce-less script to execute. The failure is not that the test page forgot to include a policy. It is that an interaction-controlled navigation created a context in which the policy's intended restriction no longer held.

The paper reports a related class of cases involving top-level data: navigation. The expected behavior is not simply “allow every link that a user activates.” Navigation is constrained by the policy and by the browser's interpretation of the destination. When an interaction permits a destination that should be blocked, the navigation itself becomes the enforcement failure. The result can be more than a script execution error: the paper notes that affected CSP cases can also undermine other guarantees, including transport and framing protections.

CSP sandbox shows the same idea without depending on a local-scheme URL. A sandbox directive can remove capabilities from a destination, including script execution, downloads, form submission, and popup creation. The study found cases in which the directive was stripped after a user reopened or duplicated a page, and cases in which a two-step interaction involving split view caused the directive not to be inherited. The browser had to preserve a restriction attached to the browsing context, but the transition created a context with more capability than the policy allowed.

The pattern generalizes to the other policies, although their state looks different. A SameSite=Strict cookie expresses a condition on whether a cross-site request may carry that cookie. If “Open link in split view” or a drag-and-drop action causes a cross-site request to include it, the browser has changed the request context in a security-relevant way. A Permissions Policy such as geolocation=() expresses a denial of a powerful feature; if a blob navigation loses that policy, code in the destination can request geolocation. COOP expresses a boundary between browsing contexts; if a split-view navigation creates a window.opener relationship that should not exist, the isolation guarantee has been weakened. HSTS expresses a transport condition; if an incognito-mode navigation uses HTTP instead of the expected HTTPS upgrade, the transition exposes a different network path.

In each case, the browser has to answer a contextual question. Which origin is relevant? Which document or request is being created? Which policy applies to that object? Does the new context inherit, copy, or reconstruct the old restriction? A browser feature that changes the sequence can expose an answer that was never exercised by a simple initial visit. BUIzz's value comes from treating that sequence as part of the policy's lifecycle.

The CSP document used by this study is itself a Working Draft updated on 13 August 2026, and the W3C publication history records a long sequence of CSP3 Working Drafts since the first public draft in 2016. That status should shape how exact claims are made. The current text is strong evidence for the draft's intended behavior and rationale, but it may be updated, replaced, or obsoleted. A careful analysis keeps three things separate: what the current specification says, what a tested browser version did, and what security consequence follows from the difference. BUIzz supplies the observation and a structured way to expose the difference; specification-aware triage determines whether the observation is a confirmed bug.

The invariant can now be stated simply: when a user takes a supported browser path, the browser should preserve the policy restriction that governs the resulting navigation or rendering context. “Preserve” does not mean that every visit produces identical network traffic or identical page behavior. It means that a legitimate contextual difference must not silently turn a blocked action into an allowed one. That is the standard BUIzz applies when it moves from the page's policy declaration to the browser UI actions that can test it.

stateDiagram-v2 [*] --> PolicyInstalled PolicyInstalled --> InitialDocument: response creates document InitialDocument --> BrowserUITransition: user opens, drags, or reopens BrowserUITransition --> LocalSchemeDestination: new context LocalSchemeDestination --> InheritedCopy: policy snapshot carried forward LocalSchemeDestination --> MissingPolicy: enforcement lost InheritedCopy --> RestrictedContext: restrictions remain MissingPolicy --> ExposedCapability: blocked action becomes available RestrictedContext --> [*] ExposedCapability --> [*]

References