## https://sploitus.com/exploit?id=DA7E875A-0206-55F2-B9D4-A4D8854AB3AB
# CVE-2026-74939 — Firefox content→parent privilege escalation
Proof of concept for a sandbox escape in Firefox 149.0a1 nightly (`2fbc0748c4`,
pre-fix). A compromised content process forges an IPDL message that makes the
**parent** load a page into a **privileged** (`privilegedabout`) process.
This is the stage-2 sandbox escape, designed to chain after a content-process RCE
(e.g. CVE-2026-2796).
## The bug (Mozilla bug 2054416)
The parent process deserializes a `nsDocShellLoadState` from content→parent IPDL
messages. The vulnerable build does not reject a content-set `RemoteTypeOverride`
field, so content can choose which process type a navigation lands in.
The fix (commit `3ec5c71b41bb`, "Validate RemoteTypeOverride") makes the
`nsDocShellLoadState` ctor reject any override on a content-triggered load.
When the override is honored — document load of `about:blank`, top-level context —
`IsolationOptionsForNavigation` sets the load's remote type to the override value,
and the page is placed in a privileged process. Sandbox boundary violated.
## Exploit overview
The override rides on `PNecko::PDocumentChannel`, a message every content process
sends for each document load (`DocumentChannelCreationArgs.loadState` is a
`nsDocShellLoadState`).
Delivery is the interesting part: raw writes to the IPC socket are silently
dropped, because IPDL messages now ride **mojo ports**. Instead, the PoC drives
the real send path from JavaScript via native calls (using the CVE-2026-2796
funcref primitive):
1. `operator new` — allocate a heap block for the `IPC::Message`
2. `IPC::Message::Message(routing, type, capacity, flags)` — placement ctor
3. `Pickle::WriteBytes` — append the forged payload
4. `MessageChannel::Send` on the PContent channel — mojo framing, port routing,
and sequence numbers are all handled natively
The payload (built by `forge.py`) carries `RemoteTypeOverride = "privilegedabout"`,
URI `about:blank`, a null principal, and runtime-leaked values (BrowsingContext id,
TriggeringRemoteType).
## Files
| File | Purpose |
| ---- | ------- |
| `privesc.html` | PoC page, run inside the compromised content process |
| `forge.py` / `forge.json` | build the forged IPDL message (self-verifying) |
| `wasm-bytes.js` | stage-1 primitives: arb R/W, funcref calls |
| `mdrive.py` / `mdrive2.py` | marionette harness to launch and drive Nightly |
| `irun` | instrumented run: lldb attach to parent + MOZ_LOG evidence |
| `profile.user.js` | Firefox profile prefs (fission on, dump enabled) |
| `parse_dc.py` | byte-exact parser for captured DocumentChannel messages |
| `scan_sentinels.py` / `extract_fields.py` | field-map scanners for captures |
## Run
```
./irun
```
## Verification
Parent-side logs (`MOZ_LOG=ProcessIsolation:5,DocumentChannel:5`) show the
process switch into the privileged process:
```
V/ProcessIsolation using remote type override (privilegedabout) for load
I/ProcessIsolation Process Switch: Changing Remoteness from 'webIsolated=http://127.0.0.1' to 'privilegedabout'
```
## References
- Mozilla bug 2054416 — fix commit `3ec5c71b41bb` "Validate RemoteTypeOverride"
- Stage-1 content RCE: CVE-2026-2796