Moderate firefox Input Validation 🔧 Commit mapped

Overview

Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionPrivilege escalation in the DOM: UI Events & Focus Handling component
ComponentDOM
Bug ClassInput Validation
Tracker2081184
Fix commit67271fe6f72e (firefox) +11/-2
CISA KEVNot listed
Creditedharuka yamazaki
Disclosed2026-10-27

Background

`BrowserParent`
the parent-process (privileged chrome) actor (dom/ipc/BrowserParent.cpp) that proxies input events to, and receives replies from, a content child process over the PBrowser IPC protocol.
`SendRealKeyEvent` / `RecvReplyKeyEvent`
the parent sends a keyboard event to the child and, when a reply is expected, records a SentKeyEventData describing what was sent; when the child replies with RecvReplyKeyEvent, the parent re-dispatches the event in the parent based on the reply.
`SentKeyEventData`
a small struct (BrowserParent.h) holding the data the parent must verify the reply against (keycode, mCodeNameIndex, mModifiers, a mUUID correlation id, and now mAlternativeCharCodes), stored in mWaitingReplyKeyboardEvents.
`mAlternativeCharCodes`
the list (at most three entries) of alternative character codes carried by a WidgetKeyboardEvent; these drive keyboard-shortcut and access-key matching in the parent.
Reply verification
RecvReplyKeyEvent compares the replied event against the stored SentKeyEventData and returns Nothing() (rejects the reply) if any field differs, to stop a misbehaving child from altering the event the parent will act on.

Root Cause Analysis

The parent’s reply-verification check in RecvReplyKeyEvent compared the stored keycode, mCodeNameIndex, mModifiers, mUUID, and edit-command state, but it never captured or compared mAlternativeCharCodes. Because the stored SentKeyEventData did not even contain the alternative char codes (the field is added to the struct in BrowserParent.h by this patch), a compromised or misbehaving content child could return a reply whose mAlternativeCharCodes differed from what the parent originally sent, and the parent would accept it. The parent then re-dispatches the keyboard event in the privileged process using the reply’s alternative char codes, which feed shortcut/access-key resolution — so the child could steer the parent into triggering keyboard shortcuts or access keys that the user’s actual keypress did not correspond to.

The patch closes the gap on both ends: SendRealKeyEvent now copies aEvent.mAlternativeCharCodes into sendKeyEventData before appending it to mWaitingReplyKeyboardEvents (moved rather than copied, with a comment noting the data is only assigned when actually stored, to avoid needless allocation), and RecvReplyKeyEvent adds NS_WARN_IF(data.mAlternativeCharCodes != aEvent.mAlternativeCharCodes) to the mismatch check so a reply that tampers with the alternative char codes is rejected. The advisory labels this “privilege escalation”; the diff substantiates the underlying defect as a missing-field integrity check on IPC reply data (the escalation to triggering unintended privileged actions follows from that gap and is the exploit framing, not an additional memory-safety sink).

Key insight
The parent verified every stored field of a keyboard-event reply except mAlternativeCharCodes — it did not even remember them — so a child could change the alternative char codes in its reply and make the privileged parent act on attacker-chosen shortcut/access-key input.

Attack Path

  1. Compromised renderer attacker has code execution in a content child process (the standard Firefox threat model for a content-process compromise).
  2. Receive a key event the parent sends a real keyboard event to the child via SendRealKeyEvent and records a SentKeyEventData awaiting a reply.
  3. Tamper the reply the child issues ReplyKeyEvent with the same keycode/modifiers/UUID (so correlation passes) but with altered mAlternativeCharCodes.
  4. Verification gap RecvReplyKeyEvent finds every stored field matching (alternative char codes were never stored or compared) and accepts the reply.
  5. Parent acts the parent re-dispatches the event in the privileged process; the attacker-chosen alternative char codes resolve to keyboard shortcuts or access keys.
  6. Primitive the child induces the parent to perform keyboard-shortcut/access-key actions not matching the real keypress (unintended privileged UI actions; the degree of escalation beyond shortcut invocation is inferred).

Impact Assessment

The defect sits in the privileged parent process and is reachable from a content child process; the precondition is a child that can send a crafted ReplyKeyEvent (i.e. a compromised or malicious renderer, not arbitrary web content directly). The gained primitive is tampering with keyboard-event reply data to trigger keyboard shortcuts or access keys the user never issued, which the parent executes with chrome privilege — a content-to-chrome escalation vector. No memory-safety corruption is shown; the strength of the escalation depends on which shortcuts/access keys are reachable (inferred). Mozilla rates it moderate.

Files Changed

  • dom/ipc/BrowserParent.cpp
  • dom/ipc/BrowserParent.h

Audit Directions

  • Other reply-verified IPC event fields
    audit SentKeyEventData and sibling “waiting reply” structures for any WidgetKeyboardEvent/WidgetMouseEvent field the parent re-dispatches but does not store and compare (e.g. char codes, key value, location flags).
  • Child-controlled event re-dispatch
    review every parent path that re-sends or re-processes an event based on a child reply (RecvReply*) for trust placed in child-supplied data that influences privileged actions.
  • Shortcut / access-key resolution inputs
    trace all inputs to parent-side keyboard-shortcut and access-key matching to confirm each is either fixed by the parent or integrity-checked against the originally dispatched event.
diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp
index b6a56e14652..877c7e8f622 100644
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -2125,7 +2125,11 @@ void BrowserParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent) {
   NS_WARNING_ASSERTION(ok, "PBrowserParent::SendRealKeyEvent() failed");
   MOZ_ASSERT(!ok || aEvent.HasBeenPostedToRemoteProcess());
   if (ok && aEvent.IsWaitingReplyFromRemoteProcess()) {
-    mWaitingReplyKeyboardEvents.AppendElement(sendKeyEventData);
+    // Although mAlternativeCharCodes contains only 3 items at most and each
+    // item is small, but let's assign it only when we actually store the data
+    // for avoiding unnecessary allocation.
+    sendKeyEventData.mAlternativeCharCodes = aEvent.mAlternativeCharCodes;
+    mWaitingReplyKeyboardEvents.AppendElement(std::move(sendKeyEventData));
   }
 }
 
@@ -2789,7 +2793,11 @@ mozilla::ipc::IPCResult BrowserParent::RecvReplyKeyEvent(
             NS_WARN_IF(data.mModifiers != aEvent.mModifiers) ||
             // The child process should've already cleared the editor commands
             // because we don't use them.
-            NS_WARN_IF(aEvent.HasEditCommands())) {
+            NS_WARN_IF(aEvent.HasEditCommands()) ||
+            // Let's avoid triggering unintended keyboard shortcuts or access
+            // keys.
+            NS_WARN_IF(data.mAlternativeCharCodes !=
+                       aEvent.mAlternativeCharCodes)) {
           // Got different event data from what we stored before dispatching an
           // event with the ID.
           return Nothing();
diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h
index 3af5f5770f6..df6377896ec 100644
--- a/dom/ipc/BrowserParent.h
+++ b/dom/ipc/BrowserParent.h
@@ -925,6 +925,7 @@ class BrowserParent final : public PBrowserParent,
     CodeNameIndex mCodeNameIndex;
     Modifiers mModifiers;
     nsID mUUID;
+    CopyableTArray<AlternativeCharCode> mAlternativeCharCodes;
   };
   nsTArray<SentKeyEventData> mWaitingReplyKeyboardEvents;
 
Loading diff…