Moderate firefox Authorization Error 🔧 Commit mapped

Overview

Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionSite isolation issue in the DOM: Navigation component
ComponentCore
Bug ClassAuthorization Error
Tracker2076816
Fix commite1b83791c015 (firefox) +1/-1
CISA KEVNot listed
CreditedShu Takahashi of Velcore Consulting Inc.
Disclosed2026-10-27

Background

`BrowsingContext`
a cross-process object representing a browsing context (roughly a frame/tab). Its state is replicated between the content process(es) and the parent process via a synchronized set of fields defined by the FIELD(...) macro list in docshell/base/BrowsingContext.h.
Synced field `CanSet` policy
each replicated field declares who is allowed to set it: CanSet::Unrestricted (any process, including a content/child process, may initiate the change), CanSet::ParentOnly (only the parent process), or CanSet::Custom (a custom validator).
`HistoryID`
an nsID identifying a browsing context’s session-history entry/identity. Session history and site-isolation decisions rely on it being trustworthy.
Site isolation / process model
in Fission, a compromised content process must not be able to influence state that the parent treats as authoritative for security/navigation decisions.

Root Cause Analysis

The replicated BrowsingContext field HistoryID was declared FIELD(HistoryID, nsID, {.mCanSet = CanSet::Unrestricted}). Unrestricted means any process participating in the sync — including an untrusted content/child process — could set HistoryID on a browsing context. Because HistoryID identifies the history/navigation identity of the context, letting a content process set it lets that process desynchronize or spoof the history identity that the parent and other processes rely on, which is a site-isolation violation: a compromised or malicious renderer can assert control over cross-process navigation/history state it should not own.

The one-line patch changes the policy to FIELD(HistoryID, nsID, {.mCanSet = CanSet::ParentOnly}), so only the parent process may set HistoryID. Content processes attempting to set it are rejected by the sync machinery, restoring the invariant that this identity field is authoritative only when written by the trusted parent. This is purely an access-control/policy change on who may write a replicated field; the diff contains no memory-safety sink.

Key insight
A security-relevant replicated BrowsingContext field, HistoryID, was writable by any process (CanSet::Unrestricted); a content process could therefore set/spoof it. Tightening it to CanSet::ParentOnly makes the parent the sole authority for that field.

Attack Path

  1. Compromise a content process The attacker runs code in a content/renderer process (e.g. via a prior renderer bug or simply a cooperating malicious page’s process). (precondition for a site-isolation bypass)
  2. Set the replicated field From that process, initiate a sync change to HistoryID on a target BrowsingContext; the Unrestricted policy accepts it.
  3. Desynchronize history identity The spoofed/attacker-chosen HistoryID propagates to the parent and other processes as the authoritative value.
  4. Abuse navigation/history Use the mismatched/controlled identity to confuse site-isolation or session-history logic (e.g. cross-context history manipulation). (concrete downstream abuse inferred; the diff proves only that content could write the field)
  5. Primitive A content process influences cross-process history/identity state it should not control — a site-isolation (authorization) bypass.

Impact Assessment

The change concerns the parent/content synchronized state of BrowsingContext; the vulnerability is exploitable from a content process and is categorized by the advisory as a site-isolation issue (moderate). No privilege beyond running in a content process is required to attempt the field set. The gained capability is the ability to set/spoof the HistoryID identity field across processes; this is an authorization/policy weakness, not memory corruption — there is no memory-safety sink in the diff. The precise security impact of a spoofed HistoryID (navigation confusion, history spoofing) is plausible but the concrete exploitation chain is inferred beyond what the one-line policy change proves.

Files Changed

  • docshell/base/BrowsingContext.h

Audit Directions

  • `CanSet::Unrestricted` fields
    enumerate every FIELD(..., {.mCanSet = CanSet::Unrestricted}) in BrowsingContext.h (and WindowContext/SyncedContext equivalents) and ask whether a compromised content process writing it is safe; identity/security-relevant fields should be ParentOnly or Custom.
  • Fields feeding security decisions
    specifically review fields consumed by site-isolation, session history, and process-selection logic for over-permissive set policies.
  • Custom setters
    check CanSet::Custom validators for fields like BrowserId to confirm they actually reject untrusted writers rather than only validating shape.
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
index 0d669468347..5ad1e3b3d3e 100644
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -175,7 +175,7 @@ struct EmbedderColorSchemes {
    * switched to another browser element this ID will remain the same but      \
    * hosted under the under the new browser element. */                        \
   FIELD(BrowserId, uint64_t, {.mCanSet = CanSet::Custom})                      \
-  FIELD(HistoryID, nsID, {.mCanSet = CanSet::Unrestricted})                    \
+  FIELD(HistoryID, nsID, {.mCanSet = CanSet::ParentOnly})                      \
   FIELD(InRDMPane, bool, {.mTopOnly = true, .mCanSet = CanSet::ParentOnly})    \
   FIELD(Loading, bool, {.mCanSet = CanSet::Unrestricted})                      \
   /* A field only set on top browsing contexts, which indicates that either:   \
Loading diff…