Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Untrusted Renderer Axiom

The foundational security posture that the browser process must treat every message from a renderer as potentially attacker-controlled, regardless of any validation the renderer claims to have performed.

Concept

Vocabulary that names a phenomenon.

“Code running in the renderer process should be assumed to be running on behalf of an attacker.” — Chromium project, docs/security/rule-of-2.md

What It Is

The axiom is a single rule the Chromium project applies to every code path that crosses from a renderer process into the privileged browser process: the renderer is hostile, every byte it sends is attacker-chosen, and any browser-side code that reads the message must validate as if no validation ran upstream. The rule is not heuristic. Reviewers, the docs/security/rule-of-2.md document, and the API-owner gate treat it as a hard architectural invariant. A Mojo handler that omits an input check on the grounds that the renderer already checked is rejected at review even when the renderer’s check happens to be correct.

The reasoning rests on the Multi-Process Architecture substrate and the Browser-Renderer Privilege Split it produced. A renderer parses web content drawn from the open web: HTML, CSS, JavaScript, image bytes, font glyphs, video streams. Any of those inputs can carry a memory-corruption primitive against the renderer’s parsers; image decoders, font shapers, and JavaScript JIT compilers are large, written in C++, and historically the source of regular vulnerabilities. The threat model treats renderer compromise as a constantly available outcome for a motivated attacker. The consequence follows: any code that runs in a privileged process and reads a renderer message has to behave as if the message arrived from a process the attacker controls, because at any given moment some renderer somewhere is in that state.

The axiom’s name is the project’s own. The Chromium security team uses the phrase “the renderer is untrusted” in design reviews; rule-of-2.md states the principle directly; the threat-model section of docs/security/ returns to it as the foundational assumption. Chromium Patterns takes the name as canonical and the rule as binding.

The axiom holds even when the renderer’s own validation logic is provably correct. A correct check inside an untrusted process is not the same fact as a correct check inside a trusted process. The renderer’s code can be exactly right at compile time; that same code is exactly what an attacker can replace via a memory-corruption primitive once the renderer is compromised, and the attacker can do so before the message is sent. Trust in a message comes from where the next check runs, not from where the first check ran.

Why It Matters

Naming the axiom converts a structural asymmetry into an enforceable rule.

The privilege split tells a contributor that the renderer is unprivileged and the browser is privileged. It doesn’t tell the contributor whether a renderer claim (“this URL is same-origin,” “this iframe is allowed to access that storage key,” “this uint32_t count fits in the buffer”) can be relied on. Without the axiom, a reasonable engineer reads the asymmetry and concludes that the renderer is a less-privileged peer whose claims are inputs to a cooperative protocol. With the axiom, the same engineer reads the same asymmetry and concludes that the renderer is a hostile peer whose claims are exploitation primitives waiting for a credulous handler. The asymmetry alone is ambiguous; the rule resolves it.

The axiom also makes “double validation” coherent rather than redundant. Reviewers and new contributors regularly notice that a Mojo interface validates inputs on both sides (the renderer rejects malformed messages before sending; the browser rejects them again before acting), and ask whether one of the checks is wasted work. The axiom answers: the renderer’s check is for the user’s benefit (it catches benign mistakes from the page’s JavaScript and produces useful error messages); the browser’s check is for the user’s safety (it stops the message even when the renderer has been replaced by an attacker). The two checks defend against different threats and neither is redundant. The Chrome Security blog has said this directly in its discussions of the Rule of 2; docs/security/mojo.md documents the rule as binding for Mojo interface authors.

For governance, the axiom gives the Three-LGTM API Owner Gate something concrete to enforce. A new Mojo interface arrives at API-owner review; the reviewers ask, for each method, what an attacker-controlled renderer can do by varying the inputs. The axiom is the lens, and the answer determines whether the interface ships. A feature whose security depends on the renderer behaving correctly is asking the API owners to suspend the axiom for its sake, and the gate refuses.

For exploit response, the axiom is what makes the Sandbox Escape Chain parse cleanly. The chain’s middle link is almost always a browser-side handler that trusted something the renderer told it. A bounty report that names such a handler is processed against the axiom as the rule violated, and severity rises when the violation is direct.

For downstream vendors building Chromium-based products (Microsoft Edge, Brave, Opera, Vivaldi, Electron applications, WebView2 embedders), the axiom is inherited along with the upstream code. Custom browser-side handlers that downstream vendors add (for telemetry, enterprise policy, or custom protocols) have to respect the axiom or they introduce attack surface the upstream project doesn’t have. CVE history shows several downstream incidents in which a vendor’s custom IPC handler skipped a validation the upstream pattern would have required; the axiom is the rule the vendor’s review process needed and didn’t run.

For AI coding agents working in Chromium and Chromium-derived code, the axiom is among the load-bearing facts to load into context. An agent that holds it produces Mojo handlers that validate every input on the browser side, and refuses to propose shortcuts that lean on the renderer’s claims. An agent that doesn’t holds neither, and produces architecturally invalid code that compiles, passes renderer-side tests, and is rejected at security review every time.

How to Recognize It

The axiom shows up at several recognizable points in the codebase, the documentation, and the review record.

In the source tree, every Mojo interface implementation hosted in content/browser/ reads as if the calling renderer were attacker-controlled. URL parameters pass through GURL and url::Origin parsers that check well-formedness rather than reading fields out of the message. Origin claims are cross-checked against the renderer’s SiteInstance identity (the browser process knows which site each renderer is hosting, from the Site Isolation machinery) rather than against an origin field in the message. Integer count and offset fields are validated through base/numerics/safe_conversions.h and the CheckedNumeric<> family before they index into buffers. The pattern is so consistent that the absence of these checks in a new browser-side handler is the most reliable signal a reviewer has of a security gap.

In the documentation, docs/security/rule-of-2.md, docs/security/mojo.md, and the threat-model section of docs/security/ name the axiom explicitly. The Rule of 2 (any feature parsing untrusted input may pick at most two of {written in C++, runs in the browser process, parses untrusted input}) is the heuristic operational form: when a feature would be the disallowed combination, the project pushes the parsing into a sandboxed utility process or refuses the design. The Rule of 2 is the easy first check a reviewer applies; the axiom is what the Rule of 2 is for.

In review threads on Gerrit and on chromium-review.googlesource.com, the axiom surfaces as one of a small set of standing comments. “This handler needs to validate the origin against the SiteInstance, not against the message field.” “This size value has to be checked before the indexed read.” “This URL needs to be parsed through GURL, not read as a string.” Each is a particular consequence of the general rule, and a contributor reading a sample of past reviews sees them recur until the underlying axiom becomes obvious.

In incident reports, the axiom is the most-cited principle when a vulnerability is rooted in IPC handling. Project Zero’s writeups of historical Chromium sandbox escapes routinely conclude with a description of which browser-side check was missing; the Chrome Security blog’s post-mortems follow the same form. The axiom is the rule the report names as violated.

How It Plays Out

Three concrete scenarios illustrate the axiom in operation.

A team adds a new Mojo interface that lets a renderer request thumbnail rendering for a list of URLs in the user’s history. The naive draft accepts a repeated string urls field on the message, hands the list to the thumbnail service, and returns the bytes. API-owner review rejects the draft on the axiom: a renderer is allowed to ask for thumbnails of URLs its session can reach, not arbitrary URLs, and the browser must check the request against the user’s actual history rather than against the renderer’s claim. The revised interface parses each URL through GURL, checks each against the user’s history records held in the browser process, and returns thumbnails only for matches. The renderer’s earlier check on the URL list still runs (it filters typo’d entries before the IPC fires), but the browser-side check is the load-bearing one for the user’s security.

A contributor encounters an existing Mojo interface with a method that takes a uint32_t count and treats it as the length of a renderer-supplied array of color stops. The count is used directly as a buffer index in the browser-side rendering path, and the contributor files a security bug. Triage classifies it as High severity on the axiom: a compromised renderer can set count larger than the array, the browser-side index overruns the buffer, and the bug is exploitable. The fix wraps the index through base::CheckedNumeric<size_t>. The IPC Integer Type Discipline pattern is updated with the incident as an exhibit.

A downstream-vendor security team audits a custom IPC handler the vendor added to expose enterprise-policy state to renderer-resident code. The handler reads a string from the renderer and uses it as a key into the vendor’s policy database. The audit applies the axiom and finds two missing checks: the renderer’s SiteInstance is never consulted, so any site can request any policy key; and the key is not validated for shape, so an attacker-supplied key can traverse the database’s internal structure. The vendor patches both, and files the post-mortem with the upstream docs/security/ team as an example of why downstream vendors need a security-review process that applies the axiom as rigorously as upstream’s.

Consequences

Holding the axiom buys several operational properties for the project.

Security review concentrates where it pays off. Code under content/browser/ that reads renderer input is read with the axiom in hand; code under content/renderer/ is read against a different threat model (renderer-internal correctness, not browser-process safety). Scarce reviewer attention follows where the axiom places it.

Mojo interface design defaults to stateless single-call methods rather than multi-call protocols. The Stateless IPC Interface pattern makes the axiom enforceable in practice: a method whose validation runs entirely on the one message it received is auditable against the axiom; a method that presumes state from a prior call isn’t. The Stateful IPC Initialization antipattern is what happens when the convenience of carrying state across calls beats the axiom in design review.

Downstream Chromium-based products inherit the rule. When a vendor’s custom IPC handler ships without a security review that applies the axiom, the resulting CVE is the vendor’s; when the vendor’s review applies the axiom rigorously, the upstream invariant holds across the integration. The cost of the axiom is paid at the integration boundary; the benefit accrues to the user.

There are real engineering costs. Validating every input on the browser side is more code, slower to write, and slower to execute than trusting the renderer. The Rule of 2’s prohibition on C++ parsing of untrusted input in the browser process forces a sandboxed-utility-process design for some features (image decoding, font shaping, video parsing), and the IPC cost is paid every time the parser runs. The project pays these costs deliberately; the axiom is the rule that says they’re worth paying.

Notes for Agent Context

Treat every input from a renderer process as attacker-controlled, with no exceptions. Inside any browser-side Mojo handler, validate every uint32_t count, offset, and size through base/numerics/safe_conversions.h (CheckedNumeric<size_t>, base::CheckMul, base::CheckAdd) before using it as a buffer index; parse every URL through GURL and read its components through url::Origin; and cross-check every origin claim against the renderer’s SiteInstance identity (RenderFrameHost::GetSiteInstance()->GetSiteInfo()), never against fields the renderer included in the message body. Never propose a browser-side handler that omits a check on the grounds that the renderer already validated the input; renderer validation doesn’t survive a renderer compromise and is never the load-bearing check. Draft every new Mojo method as a stateless single-call method that validates everything it needs from the one message it receives; refuse to chain it onto state from a prior Init() call.

Sources

The canonical primary source is the Chromium project’s docs/security/rule-of-2.md, which states the principle directly in its opening paragraph and uses it as the premise for the Rule of 2 heuristic the rest of the page formalizes. docs/security/mojo.md is the operational extension to Mojo interface authors, naming the validation requirements every browser-side method has to meet. The threat-model section of docs/security/ (docs/security/side-channel-threat-model.md and surrounding pages) is the design-level statement of why the renderer is treated as hostile by default. The Chrome Security blog, in its public discussions of the Rule of 2 and of historical sandbox escapes, names the axiom as the underlying principle and walks the consequences for downstream vendors. Project Zero’s analyses of past Chromium sandbox escapes (Ned Williamson’s writeups on IPC bugs, the V8 escape chains documented by other team members) consistently identify a missing browser-side check as the proximate cause; the implicit reference is to the axiom every time.

Technical Drill-Down