Moderate firefox Spoofing 🔧 Commit mapped

Overview

Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionSpoofing issue in the DOM: Core & HTML component
ComponentCore
Bug ClassSpoofing
Tracker2067647
Fix commitdb70a958f3f3 (firefox) +2/-1
CISA KEVNot listed
CreditedMohamed Mbarek
Disclosed2026-10-27

Background

Pointer Lock API
element.requestPointerLock() hides the cursor and routes raw mouse movement to a page. Because it removes the visible cursor, Firefox shows a transient notification naming the origin that locked the pointer, so the user knows which site is in control.
`PointerLockParent` (JSWindowActor)
The parent-process actor in browser/actors/PointerLockParent.sys.mjs that receives the PointerLock:Entered message from the content process and drives the UI by calling browser.documentGlobal.PointerLock.entered(<origin>).
`WindowGlobalParent` / `documentPrincipal`
Each frame (including cross-origin subframes) has its own WindowGlobalParent with a documentPrincipal. this.manager is the actor’s window global, i.e. the frame that sent the message, which can be a subframe.
`browsingContext.top.currentWindowGlobal.documentPrincipal`
The principal of the top-level document of the tab, regardless of which subframe triggered the action.

Root Cause Analysis

When handling PointerLock:Entered, the parent built the origin string shown in the pointer-lock notification from this.manager.documentPrincipal.originNoSuffix — the principal of the frame that requested the lock. Pointer lock can be requested from a cross-origin iframe, so this.manager may be a subframe window global whose origin differs from the top-level page. The notification therefore displayed the subframe’s origin as the site that locked the pointer, which an embedding attacker could exploit to make the warning name an arbitrary origin rather than the real controlling context.

The one-line fix replaces the source of the origin with this.manager.browsingContext.top.currentWindowGlobal.documentPrincipal.originNoSuffix, i.e. always the top-level document’s principal. After the patch the pointer-lock notification reflects the top-level origin the user actually sees in the address bar, closing the spoofing gap. The change touches only the string passed to PointerLock.entered; the lock mechanics are unchanged.

Key insight
The pointer-lock notification derived its displayed origin from the requesting frame’s principal instead of the top-level document’s, so a cross-origin iframe could cause the warning to name a different origin than the one in control.

Attack Path

  1. Embed Attacker’s top-level page embeds a cross-origin iframe (or is itself embedded such that the requesting frame’s origin differs from the top), (inferred: standard web embedding).
  2. Request lock Script in the subframe calls requestPointerLock(); the content process sends PointerLock:Entered.
  3. Wrong origin resolved (pre-patch) PointerLockParent reads this.manager.documentPrincipal.originNoSuffix — the subframe’s origin — and passes it to PointerLock.entered.
  4. Misleading notification The pointer-lock warning displays the subframe origin, not the top-level origin the user associates with the tab.
  5. Primitive Origin spoofing in a security-relevant notification: the user is told a different site controls their pointer than the one in the address bar, which can be leveraged for UI deception while the cursor is hidden.

Impact Assessment

Front-end/parent-process spoofing issue; no memory safety impact and no code execution. The gained capability is displaying an attacker-chosen (subframe) origin in the pointer-lock notification, misleading the user about which site has captured the pointer — consistent with the “moderate” spoofing rating. Precondition is only that the page can request pointer lock from a frame whose origin differs from the top-level document; no special privilege is needed.

Changed Functions

FunctionChangeNotes
switch
browser/actors/PointerLockParent.sys.mjs
modified

Files Changed

  • browser/actors/PointerLockParent.sys.mjs

Audit Directions

  • Other actor-side principal uses
    Audit other JSWindowActor parents that build user-facing security strings from this.manager.documentPrincipal; many permission/notification UIs should use the top browsing context’s principal, not the sending frame’s.
  • Pointer-lock UI consistency
    Verify every place the pointer-lock UI is updated (entered/exited/warning text) uses the same top-level origin source so they cannot disagree.
  • Subframe-triggered prompts generally
    Review fullscreen, autoplay, and similar notifications for the same requesting-frame-vs-top-frame origin confusion.
diff --git a/browser/actors/PointerLockParent.sys.mjs b/browser/actors/PointerLockParent.sys.mjs
index 97993953d71..8ee3f0e13af 100644
--- a/browser/actors/PointerLockParent.sys.mjs
+++ b/browser/actors/PointerLockParent.sys.mjs
@@ -8,7 +8,8 @@ export class PointerLockParent extends JSWindowActorParent {
     switch (message.name) {
       case "PointerLock:Entered": {
         browser.documentGlobal.PointerLock.entered(
-          this.manager.documentPrincipal.originNoSuffix
+          this.manager.browsingContext.top.currentWindowGlobal.documentPrincipal
+            .originNoSuffix
         );
         break;
       }
Loading diff…