Low firefox Spoofing 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionSpoofing issue in the DOM: Core & HTML component
ComponentCore
Bug ClassSpoofing
Tracker2035027
Fix commit529974613f2d (firefox) +3/-2
CISA KEVNot listed
CreditedJody Ritonga
Disclosed2026-06-16

Background

`GeckoSession`
the GeckoView Java class that represents a single web content session and routes content events to registered delegates.
`SelectionActionDelegate`
the delegate interface an embedding app implements to show and hide text-selection action UI and clipboard permission prompts.
`onDismissClipboardPermissionRequest`
the SelectionActionDelegate callback that tells the app to tear down any in-flight clipboard permission request UI.
`onHideAction`
the SelectionActionDelegate callback that hides existing selection-action UI, here invoked with HIDE_REASON_NO_SELECTION.

Root Cause Analysis

When an app swaps or clears the SelectionActionDelegate on a GeckoSession, the code path in setSelectionActionDelegate explicitly cleans up the outgoing delegate because Gecko does not track the old delegate itself. The pre-fix code invoked only onHideAction on the old delegate, so it dismissed the selection-action UI but left any outstanding clipboard permission request UI still displayed. This violated the invariant that all UI owned by a delegate must be dismissed when that delegate is retired, letting a stale clipboard-permission prompt survive a delegate change.

The fix captures the outgoing delegate in oldDelegate and additionally calls oldDelegate.onDismissClipboardPermissionRequest(this), ensuring the clipboard prompt is torn down alongside the selection UI. This works because both dismissal callbacks are now driven against the same old delegate at the moment it is replaced, closing the cleanup gap.

Key insight
The single mistake was cleaning up only one of the two UI surfaces a SelectionActionDelegate can own during delegate replacement; the fix adds the missing onDismissClipboardPermissionRequest call so the clipboard permission prompt cannot outlive the delegate that raised it.

Attack Path

  1. Trigger a clipboard prompt Attacker content induces a clipboard permission request so the current SelectionActionDelegate displays its permission UI.
  2. Force a delegate change A subsequent action causes the app to set or clear the SelectionActionDelegate via setSelectionActionDelegate.
  3. Stale UI persists Because only onHideAction fired, the clipboard permission request UI from the old delegate remains on screen after the delegate is gone.
  4. Spoofing window The lingering, orphaned prompt can misrepresent state or context to the user, who may act on a request no longer backed by a live delegate.

Impact Assessment

An attacker gains a UI-spoofing opportunity in the GeckoView embedding app (Firefox for Android and other GeckoView apps), where a clipboard permission prompt can remain visible after its owning delegate is replaced. Exploitation requires triggering a clipboard permission request and then causing a SelectionActionDelegate change; impact is rated low and limited to misleading UI rather than memory corruption.

Files Changed

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java

Audit Directions

  • Delegate replacement cleanup
    Whenever a delegate is swapped or cleared, verify every UI surface it can present is dismissed, not just the most obvious one.
  • Multi-callback lifecycles
    Audit delegate interfaces with more than one show/hide pair (onHideAction plus onDismissClipboardPermissionRequest) to confirm all teardown callbacks fire together.
  • Orphaned permission prompts
    Look for permission or consent UI that can outlive the object that raised it, especially across ownership or context transitions in embedding-layer glue code.
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
index fdab52f889b..5e47ed4f1f9 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -3593,8 +3593,9 @@ public class GeckoSession {
       // When the delegate is changed or cleared, make sure onHideAction is called
       // one last time to hide any existing selection action UI. Gecko doesn't keep
       // track of the old delegate, so we can't rely on Gecko to do that for us.
-      getSelectionActionDelegate()
-          .onHideAction(this, GeckoSession.SelectionActionDelegate.HIDE_REASON_NO_SELECTION);
+      final SelectionActionDelegate oldDelegate = getSelectionActionDelegate();
+      oldDelegate.onHideAction(this, GeckoSession.SelectionActionDelegate.HIDE_REASON_NO_SELECTION);
+      oldDelegate.onDismissClipboardPermissionRequest(this);
     }
     mSelectionActionDelegate.setDelegate(delegate, this);
   }
Loading diff…