CVE-2026-117995
Overview
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 thePBrowserIPC protocol. - `SendRealKeyEvent` / `RecvReplyKeyEvent`
- the parent sends a keyboard event to the child and, when a reply is expected, records a
SentKeyEventDatadescribing what was sent; when the child replies withRecvReplyKeyEvent, 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, amUUIDcorrelation id, and nowmAlternativeCharCodes), stored inmWaitingReplyKeyboardEvents. - `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
RecvReplyKeyEventcompares the replied event against the storedSentKeyEventDataand returnsNothing()(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).
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
- Compromised renderer attacker has code execution in a content child process (the standard Firefox threat model for a content-process compromise).
- Receive a key event
the parent sends a real keyboard event to the child via
SendRealKeyEventand records aSentKeyEventDataawaiting a reply. - Tamper the reply
the child issues
ReplyKeyEventwith the same keycode/modifiers/UUID (so correlation passes) but with alteredmAlternativeCharCodes. - Verification gap
RecvReplyKeyEventfinds every stored field matching (alternative char codes were never stored or compared) and accepts the reply. - 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.
- 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
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.cppdom/ipc/BrowserParent.h
Audit Directions
- Other reply-verified IPC event fieldsaudit
SentKeyEventDataand sibling “waiting reply” structures for anyWidgetKeyboardEvent/WidgetMouseEventfield the parent re-dispatches but does not store and compare (e.g. char codes, key value, location flags). - Child-controlled event re-dispatchreview 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 inputstrace 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.
Patch
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;