CVE-2026-16399
Overview
Background
- `BrowserParent`
- the parent-process actor that manages a single content process’s top-level frame and mediates its IPC messages.
- `WindowGlobalParent` (`WGP`)
- the parent-process representation of a specific window/document (a global) living in a content process.
- `BrowsingContext`
- the parent-process object modeling a frame or tab whose subtree ownership determines which process is allowed to host its documents.
- Site isolation
- the security model that keeps documents of different origins in separate content processes so a compromised process cannot act on another origin’s frames.
Root Cause Analysis
The vulnerable path is BrowserParent::RecvNewWindowGlobal in dom/ipc/BrowserParent.cpp, which handles a content process’s request to register a new WindowGlobalParent for a given browsingContext.
Before the fix, the handler validated only that the target browsingContext belonged to a BrowsingContextGroup known for the child process, but never confirmed that the browsingContext actually lived within this BrowserParent’s frame subtree. This broke the invariant that a content process may only create globals for browsing contexts it legitimately owns — a compromised child could name an arbitrary sibling or unrelated BrowsingContext in the same group.
The fix adds an explicit check: unless the target is this actor’s own mBrowsingContext, its parent WindowGlobalParent must exist and must be managed by this same BrowserParent (parentWgp->Manager() != this), otherwise the message is rejected with IPC_FAIL. This works because it forces the new global to attach only to a parent window already owned by this process, keeping the parent-side frame tree consistent with process ownership.
BrowsingContext’s parent window context to be managed by the requesting BrowserParent.Attack Path
- Compromise a content process An attacker gains code execution in a content process (e.g., via a separate renderer bug) so it can forge IPC messages to the parent.
- Target a foreign BrowsingContext
The process sends
RecvNewWindowGlobalnaming aBrowsingContextthat shares itsBrowsingContextGroupbut is not in its own frame subtree. - Pass the weak check
The pre-fix
IsKnownForChildIDgroup check succeeds because the context is merely in the same group. - Register an illegitimate global
A
WindowGlobalParentis created and attached for a document the process should not host, violating site isolation.
Impact Assessment
WindowGlobalParent for a BrowsingContext outside its ownership, letting one process influence or spoof another origin’s global and undermining cross-origin isolation guarantees. The effect is in the trusted parent process’s model of the frame tree, driven from a content child. The precondition is prior control of a content process capable of sending IPC; the issue is rated moderate/medium with no memory-corruption primitive shown in the diff.Files Changed
dom/ipc/BrowserParent.cpp
Audit Directions
- IPC ownership validationAudit other
Recv*handlers that accept aBrowsingContextor context ID from a child and confirm each verifies subtree/process ownership, not just group membership. - Group-membership-as-authorizationFlag any use of
IsKnownForChildIDor similar group checks as the sole gate on a privileged cross-process operation. - Parent/child tree consistencyLook for places that attach
WindowGlobalParentor frame objects without checking that the parent context is managed by the same actor (Manager() == this).
Patch
diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp
index 6a6126b3640..ca69f14836c 100644
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -1367,6 +1367,11 @@ IPCResult BrowserParent::RecvNewWindowGlobal(
if (!browsingContext->Group()->IsKnownForChildID(OtherChildID())) {
return IPC_FAIL(this, "Invalid BrowsingContextGroup for process");
}
+ WindowGlobalParent* parentWgp = browsingContext->GetParentWindowContext();
+ if (browsingContext != mBrowsingContext &&
+ (!parentWgp || parentWgp->Manager() != this)) {
+ return IPC_FAIL(this, "BrowsingContext is not in BrowserParent subtree");
+ }
if (!aInit.principal()) {
return IPC_FAIL(this, "Cannot create without valid principal");
}
@@ -1375,7 +1380,6 @@ IPCResult BrowserParent::RecvNewWindowGlobal(
}
nsCOMPtr<nsIURI> docURI = aInit.documentURI();
- WindowGlobalParent* parentWgp = browsingContext->GetParentWindowContext();
// Ensure we never load a document with a content principal in
// the wrong type of webIsolated process