Skip to content

Latest commit

 

History

History
368 lines (316 loc) · 33.9 KB

PARITY.md

File metadata and controls

368 lines (316 loc) · 33.9 KB

Security & privacy parity — LibreWolf desktop vs. Redoubt (Android)

Status: M5 deliverable (LW-M5-06), the close-out of milestone M5. Every status below is backed by measurement, not intent — a binary scan of libxul.so, a running-build capture, a config parse, or an upstream bug number. Where a status depends on a measurement we could not run this session (no device, no test server), the row is marked PENDING and is not counted as verified (see §4).

1. The bottom line — read this first

Redoubt has no Gecko content sandbox. MOZ_SANDBOX is off on Android, toolkit.mozbuild:37 never traverses security/sandbox, and every security.sandbox.* pref is inert. Upstream never finished the port (bug 1660102, still NEW and touched 2025-05; bug 2040639, "enabling it yields build errors"). This is a platform fact, not a configuration choice, and it is the single largest containment gap versus desktop.

What recovers most, not all, of it:

  • Per-site process isolation — fission.webContentIsolationStrategy locked to ISOLATE_HIGH_VALUE (LW-M5-01). Stock Fenix ships 0 (ISOLATE_NOTHING); this is a genuine win over the browser we build from.
  • Process separation — Partial, from 158.0-2: Android 12+ isolated, Android 8-11 not. isolatedProcess plus the app zygote (LW-M5-02) gave the content process a distinct uid in 157.0-2, but an isolated content process cannot decode H.264 or AAC (upstream bug 1810736), so most web video failed and 157.0-3 pinned both off (LW-M7-43). 158.0-2 turns them back on for Android 12+ (API 31+) only, with H.264/HEVC/AAC decoded by the NDK MediaCodec in the RDD and Utility processes and software codecs kept in the isolated process (LW-M7-50, owner decision 2026-10-11 "158.0-2, Android 12+ only"; docs/android/ISOLATION-MEDIA.md). On Android 8-11 content still runs under the app's uid, as in stock Fenix, until a flake seen with upstream's media prefs on the API 30 emulator is understood. The feasibility study behind it is ISOLATION-MEDIA-STUDY.md (LW-M7-48).
  • JS/WASM sandboxing — 52 RLBox modules are built (measured in libxul.so).

The two irreducible gaps, stated plainly, are the Gecko content-process sandbox (above, §3.1) and the loss of the desktop build's signing-key identity (§3.2).

2. The parity matrix

Legend: Equivalent = the same effective security/privacy property as desktop; Partial = present or configured but not fully honoured, with the shortfall stated in the mechanism; Absent = not present, no Android equivalent. "Measured by" names the evidence type so a reader can tell measurement from assertion.

# Property Desktop Android Mechanism / evidence
1 Gecko content-process sandbox (MOZ_SANDBOX) ON Absent Not compiled; toolkit.mozbuild:37 skips security/sandbox; security.sandbox.* inert. Upstream port unfinished (bugs 1660102, 2040639). Mitigated by rows 2–4. Measured by: build config + upstream bugs. [ROADMAP, SANDBOX-SPIKE]
2 Per-site process isolation (Fission) ISOLATE_HIGH_VALUE Equivalent (stronger than stock) Locked to ISOLATE_HIGH_VALUE (LW-M5-01); stock Fenix ships 0. Measured by: running-build pref read. [no-nimbus.patch, LW-M5-01]
2a Content process isolation (separate uid, isolated_app) n/a on desktop (the Gecko sandbox, row 1, is the desktop mechanism) Partial: Android 12+ isolated; Android 8-11 not From 158.0-2 (LW-M7-50, owner decision 2026-10-11 "158.0-2, Android 12+ only"): GeckoProvider turns isolatedProcess + app zygote on for SDK >= 31; web content runs as u:r:isolated_app with an isolated uid and cannot open the profile. H.264/HEVC/AAC are parsed in :rdd/:utility (app uid), every other codec only in the isolated process. Android 8-11: content under the app uid as in 158.0-1 and stock Fenix. Measured by: android-smoke.sh --check-isolation on API 34 and API 31 (ON) and API 30 (OFF), and ps -A -o LABEL on a Pixel 10 Pro (Android 17), of the prototype dev APK (2fa22e51), not of a 158.0-2 build; the 158.0-2 dev APK has not been measured on the phone yet. 2026-10-14 (launch QA): the signed 158.0-2 arm64 release on a Pixel 9a (Android 17) and a Xiaomi Mi 8 (LineageOS, Android 15): web content ran as isolated_app (ps -A -Z) on both, and 1080p H.264, VP9 and AV1 test clips played to the end with 0 dropped frames. [ISOLATION-MEDIA, evidence/lw-m7-50/release-158.0-2]
3 JS/WASM sandboxing (RLBox) ON Equivalent 52 RLBox modules present. Measured by: binary scan of libxul.so. [SANDBOX-SPIKE]
4 Compiler memory hardening (CFI, PHC, rosegment, …) ON Equivalent (some stronger) All desktop flags present + PHC + rosegment; Android STL hardening (libc++ EXTENSIVE) is stronger than desktop _GLIBCXX_ASSERTIONS. Residual: 32-bit ARM lacks -fstack-clash-protection. Measured by: binary scan of libxul.so. [hardening-flags.md]
5 HTTPS-only mode ON Partial (emulator-measured 2026-10-09/10 on 157.0-3; phone check pending) On by default through Fenix's own setting (privacy-defaults.patch; dom.security.https_only_mode=true, not locked, so the user can turn it off in Settings). Measured on 157.0-3 (API 34 emulator, local servers): a top-level http:// load shows the HTTPS-only interstitial and loads only after "Continue to HTTP site"; an http:// URL to a host that speaks TLS is upgraded silently and ends as a secure context; the exception is per origin (another port still gets the interstitial) and stored as https-only-load-insecure with expireType=1 (session). Device-pending: public sites, and whether the exception really ends with the session. Kept at Partial until the phone check passes (owner decision 2026-10-10: the emulator result does not raise a row on its own). Measured by: android-smoke.sh --check-https-only (rows https-only-interstitial, https-only-upgrade, https-only-exception-scope). [evidence/lw-m7-49, DEVICE-CHECKS §1]
6 DNS-over-HTTPS OFF by choice (mode 5), Quad9 preset, dns4all fallback Partial — defaults match, resolver not measured (emulator pref dump and Settings screen 2026-10-14; phone check pending) Corrected 2026-10-14 (LW-M7-51): this row described Beta 1 and called desktop's mode 5 "ON"; mode 5 is DoH off by choice on both. privacy-defaults.patch (LW-M7-09, shipped since Beta 2) makes Fenix's own defaults LibreWolf's: DoH off (mode 5) and LibreWolf's provider catalog with the dns4all default, minus Mullvad since doh-mullvad-migration.patch. Fenix still writes network.trr.mode/network.trr.uri on every cold start (Core.kt → GeckoEngine.kt), but now with these values, and the user turns DoH on in Settings > DNS over HTTPS. Measured by: the 158.0-2 acceptance pref dump on the API 34 emulator (evidence/lw-m7-50/release-158.0-2/device-api34/full-suite-1-prefs.txt: network.trr.mode 5, network.trr.uri https://dns10.quad9.net/dns-query, unlocked, no user value; the same rows are in expected-prefs.txt, which the pref audit enforces) and Settings > DNS over HTTPS reading "Off" on a new profile of the LW-M7-51 port build (158.0-2 plus LW-M7-38), whose pref dump has the same two rows (evidence/lw-m7-51/). Not measured: which resolver a DoH-on profile really uses (FEATURE-PARITY F05). Locking is still not the remedy: Settings owns both prefs (must-not-lock.txt, network.trr.*). [must-not-lock.txt]
7 Certificate revocation (CRLite + OCSP off) ON (CRLite mode 2, OCSP disabled) Partial (emulator-measured 2026-10-09/10 on 157.0-3; phone check pending) The cfg posture is applied on the running build (OCSP.enabled=0, crlite_mode=2; startup-injected opposites were overwritten by the cfg). Measured on 157.0-3: no OCSP request is ever sent (0 requests to a live responder named in the AIA of good, revoked and closed-port leaves, which all load); a stapled "revoked" response is refused (SEC_ERROR_REVOKED_CERTIFICATE); must-staple without a staple is refused. With the real network, CRLite filters were loaded about 45 s after a first start (76 filters later) and revoked.badssl.com was refused by CRLite (it loaded with crlite_mode=0). Shared with desktop, not an Android gap: no WebPKI revocation check before the first filter sync, and none for revocations newer than the filters (a Let's Encrypt test certificate revoked two days earlier still loaded). Naming note: LibreWolf ships CRLite mode 2 with OCSP disabled, not "OCSP hard-fail" (report item e). Kept at Partial until the phone check passes (owner decision 2026-10-10: the emulator result does not raise a row on its own). Measured by: android-smoke.sh --check-revocation + a live CRLite run. [evidence/lw-m7-49, DEVICE-CHECKS §4]
8 Modern TLS floor (min ≥ 3, no 0-RTT, no deprecated ciphers) ON Partial (emulator-measured 2026-10-09/10 on 157.0-3; phone check pending) Running build: security.tls.version.min=3, max=4, enable-deprecated=false, enable_0rtt_data=false. Measured on 157.0-3 against four local servers pinned to one version each: TLS 1.0 and 1.1 refused (SSL_ERROR_PROTOCOL_VERSION_ALERT, no handshake completed on the server), TLS 1.2 and 1.3 connect. The negative control (min=1, deprecated on) lets all four connect, so the probe can fail. Device-pending: public servers (BadSSL). Kept at Partial until the phone check passes (owner decision 2026-10-10: the emulator result does not raise a row on its own). Measured by: android-smoke.sh --check-tls-floor. [evidence/lw-m7-49, DEVICE-CHECKS §3]
9 Resist Fingerprinting ON (incl. window-size normalization) Partial — coherent on the emulator (2026-10-10); real-device values pending RFP master ON (shared common.cfg) + block_mozAddonManager + GPC; window-size/letterboxing are desktop-only prefs (letterboxing is off on desktop too, so not a loss). Measured on 157.0-3 (17/17 items): window, worker and the request header agree on Firefox's Android spoof profile (Android 10; Mobile UA with the real major version, Linux armv81, buildID 20181001000000, 4 cores, 5 touch points), screen = window size, colour depth 24, time zone Atlantic/Reykjavik with the device on Europe/Zurich, timers clamped to 16.67 ms, no Client Hints; canvas readback is randomized. With RFP off the probe fails 12/17. Still Partial because it is a mobile profile, not desktop's (by design), and the values that identify a real phone (window size and DPR, installed fonts, GPU) can only be read on one. Measured by: android-smoke.sh --check-rfp-coherence; phone: android-device-probe.py. [RFP-ANDROID, evidence/lw-m7-49, DEVICE-CHECKS §2]
10 Global Privacy Control ON Equivalent Not locked, and must not be: a visible Fenix switch owns privacy.globalprivacycontrol.enabled (tracking_protection_preferences.xml:127-130), but the only value it can push through GeckoView:SetDefaultPrefs is true, which is ours; functionality.enabled / pbmode.enabled are reached by nothing at stage 5b. Measured by: code trace (must-not-lock.txt, commit 7c92b22). [RFP-ANDROID]
11 Enhanced Tracking Protection (strict) ON Equivalent lockPref in settings/android.cfg:341 (must-lock.txt); the Fenix Tracking Protection selector still moves but no longer changes behaviour — the same UI/pref split desktop ships (bare-prefs.md). Measured by: source + running-build pref read (LW-M3-09). [RFP-ANDROID, POLICIES]
12 Cookie partitioning / SameSite ON Equivalent network.cookie.cookieBehavior and its .pbmode / .optInPartitioning variants are lockPref (must-lock.txt), so stage 5b cannot move them. Measured by: source (must-lock.txt, generated by gen-android-locks.py). [network-posture]
13 Shared LibreWolf security/privacy patch set common ∪ desktop (60) common ∪ android (42) Equivalent for the shared (common) set. 24 common patches apply to both targets; 36 desktop-only do not reach Android; 18 are Android-specific (isolation, telemetry removal). Measured by: board.py --check-scope. [PATCH-SCOPE]
14 Telemetry / experiments / sponsored content patched off Equivalent (broader removal) no-adjust, no-glean, no-nimbus, no-nimbus-toolkit, no-gms, no-onboarding (all android.txt); 2,623 GMS dex classes → 0. Measured by: dex class count on a running build. [PATCH-SCOPE, POLICIES]
15 Enterprise policy keys (22) via policies.json Partial policies.json engine absent on Android (Services.policies undefined); all 22 keys mapped to other mechanisms; gaps P1–P8 (Nimbus P2, Glean P3, default-browser prompt P4, extension-type restriction P5, sponsored/contile P6, HttpsOnlyMode P7). Measured by: policy-key mapping + running build. [POLICIES]
16 Signing-key / codebase identity LibreWolf/Mozilla code-signing trust root Absent (irreducible) Fork (Redoubt), not the LibreWolf project. Android identity is a distinct trust root — the org.redoubtbrowser applicationId plus the signing key (LW-M6-01) — and the current build still ships as org.mozilla + .fenix.debug. It cannot carry the desktop build's code-signing identity. [IDENTITY, ROADMAP]
17 Cookie-banner handling No service: Firefox 156 removed the cookie banner service; LibreWolf's uBO catalog keeps the cookie-notice lists off Different mechanism, on by default (since 2026-10-02) Firefox 156 removed toolkit/components/cookiebanners, the cookiebanners.* prefs and GeckoView's Cookie Banner Handling API ("no replacement", bug 2058143), so the 153 betas' packaged rules and controls (LW-M7-13/23) are retired on both targets. Owner decision: Android turns on uBlock Origin's "EasyList/uBO – Cookie Notices" lists (fanboy-cookiemonster, ublock-cookies-easylist) by default through its own uBO catalog (settings/android.cfg librewolf.uBO.assetsBootstrapLocation → assets/uBOAssets.android.json at a pinned Redoubt commit; the catalog names no self-update URL, so uBO keeps the one it bootstrapped; LW-M7-41); the user turns them off in uBO's "Filter lists" pane. Not equivalent to the old service: a filter list hides the banner or blocks its script and never clicks "reject", so a site records no refusal. Fresh installs get them from the catalog; existing profiles (Beta 3 or earlier, or an offline first run) get them turned on once by patches/android/ubo-cookie-lists-migration.patch (owner decision for Beta 5), which appends both to a uBO selection naming neither before uBO reads it and then sets librewolf.uBO.cookieListsMigrated, so a later opt-out holds. Measured by: config parse + bundled-XPI key check (scripts/android-cookie-banner-smoke.py --tree, PASS on the 157 tree); hosted catalog PENDING until the pinned commit is on CPlusPlus17/Redoubt; migration logic by scripts/tests/test-ubo-cookie-lists-migration.js (13 cases, run on the patch's own lines), and the smoke's migration check (packaged ExtensionStorageIDB.sys.mjs + Extension.sys.mjs) FAILs on the Beta 4 rc3 APK, which predates it; on the Beta 5 candidate (built from cdeadd6c, emulator, evidence/lw-m7-41/migration/) it PASSes, a Beta 4 offline-first-run profile and a Beta 3 profile get both lists once on the first start after adb install -r (ticked, cached and blocking on example.org; Beta 3's other uBO settings unchanged), an opt-out survives two restarts and a reinstall, and a fresh online install is a no-op.

Auxiliary-process containment (GPU / RDD / socket / utility / media): not counted as an independent row. On desktop several of these run under per-process seccomp sandboxing; on Android that per-process sandboxing has no equivalent — they run under the app's own uid, and since LW-M7-43 so does content, without the content sandbox that would complement them. This is a consequence of row 1, not a separate mechanism. [SANDBOX-SPIKE]

3. The irreducible gaps

3.1 The Gecko content-process sandbox

Stated in §1. It is neither a policy decision nor a small port: upstream (bug 1660102, NEW; bug 2040639, NEW, "enabling it yields build errors") has not finished it, and the cost of finishing it is 4–8 engineering-weeks to a first build and 6–12 engineering-months to ship-safe, with permanent maintenance (SANDBOX-SPIKE §7). The recorded recommendation is not to pursue MOZ_SANDBOX: the marginal gain over isolated_app + RLBox is kernel-attack-surface only (and isolated_app itself is on only for Android 12+ since 158.0-2, LW-M7-50), and it is undercut by the no-telemetry SIGSYS risk on a vendor-kernel fleet (SANDBOX-SPIKE §8).

3.2 The signing-key / codebase identity

This is a fork, not the LibreWolf project. The MPL-2.0 licence grants the code, not the name or the trust identity (§3.4 grants no rights in any contributor's trademarks). The Android build's identity is a separate trust root — the org.redoubtbrowser applicationId plus the signing key generated in LW-M6-01 — and it cannot be the desktop build's code-signing identity. Both the applicationId and the key are one-way decisions (a change strands every install), which is why neither may be decided carelessly (IDENTITY.md, ROADMAP).

4. What is NOT verified (PENDING)

Updated 2026-10-10 (LW-M7-49). The honoured layer of rows 5, 7, 8 and 9 is now measured on the 157.0-3 APK on an API 34 emulator against local servers, each check with a negative control that makes it fail (evidence/lw-m7-49/README.md). Rows 5, 7 and 8 stay Partial until the phone pass in DEVICE-CHECKS.md is done; the owner raises them after it. What stays pending is what an emulator cannot show, listed with the phone steps in DEVICE-CHECKS.md (below).

157.0-3 has since been superseded by 157.0.1-1 (2026-10-09). The measurement was not repeated and does not need to be for these rows: 157.0.1-1 is built from the same settings/, and its only patch changes since 157.0-3 (delete-on-quit-swipe.patch, ubo-preinstall.patch) set none of the prefs these rows rest on (dom.security.https_only_mode*, security.OCSP.*, security.pki.crlite_mode, security.tls.*, privacy.resistFingerprinting*).

Pending on a phone:

  • Rows 5, 7, 8 on a phone: HTTPS-only and the TLS floor against public servers, CRLite filter sync on the phone's network, and whether an HTTPS-only exception really ends with the session.
  • Row 9 on a phone: the values that identify a real device (window size and DPR, installed fonts, GPU/WebGL, locale) under RFP. The emulator measured coherence of the spoofed values, not how many real phones share them.

scripts/android-network-check.sh and scripts/android-rfp-check.sh remain the static gates (exit 3 for their own honoured layer); the live probes are the android-smoke.sh flags above.

Still pending from before:

  • Honoured behaviour for policy gaps P1–P8 (row 15): needs a device to confirm each Kotlin-side behaviour.
  • Cookie-notice lists selected on a device (row 17): needs a fresh install, then uBO's dashboard ("Filter lists" → "Annoyances"). The build side is checked by scripts/android-cookie-banner-smoke.py; its --fetch check stays PENDING until assets/uBOAssets.android.json is on Redoubt's main branch, and until then uBO uses the catalog inside its XPI.

Both static check scripts are gates with a passing negative control, so a regression in the configured layer is caught automatically. The honoured layer of rows 5, 7, 8 and 9 is caught by the smoke flags; for rows 15 and 17, and for the phone-only values above, it still needs a device-equipped session.

5. The agreed public wording

Redoubt ships the same privacy configuration and the same Gecko-level security patches as LibreWolf desktop, on a platform whose process containment is weaker — and we publish exactly where.

Quoted verbatim from ROADMAP.md and the LW-M5-06 task, which states: "Do not soften it."

Status of this wording: SIGNED OFF, approved for publication as written.

APPROVED      2026-09-06
APPROVED BY   Manuel Gysin (owner)
SCOPE         the wording above, verbatim, and its use on the download page

Approved unchanged, which is what the task asked for — LW-M5-06 says "Do not soften it", and it has not been softened. redoubtbrowser.org is the decided and registered domain (IDENTITY.md, 2026-08-23); an earlier revision of this paragraph called it an open placeholder, which it had stopped being.

LW-M7-02 may now put this text on the download page verbatim, not paraphrased and not summarised. The sentence promises "we publish exactly where", and the thing it promises to publish is the table in section 1 of this file — including row 1's absent content-process sandbox and row 6's DoH, which Fenix overwrites on every cold start (since Beta 2 with LibreWolf's values; the resolver a DoH-on profile uses is not measured). Publishing the sentence without a reachable link to that table would make it false.

6. Sources

  • docs/android/parity/hardening-flags.md (LW-M5-03) — row 4
  • docs/android/parity/network-posture.md (LW-M5-05) — rows 5–8, 12
  • docs/android/parity/RFP-ANDROID.md (LW-M5-04) — rows 9–11
  • docs/android/POLICIES.md (LW-M3-06) — rows 11, 14, 15
  • docs/android/PATCH-SCOPE.md (LW-M1-01/12) — rows 13, 14
  • docs/android/SANDBOX-SPIKE.md (LW-M5-07) — rows 1, 3, the auxiliary note, §3.1
  • docs/android/IDENTITY.md, docs/android/ROADMAP.md — row 16, §3.2, §5
  • Gates: scripts/android-network-check.sh (LW-M5-05), scripts/android-rfp-check.sh (LW-M5-04) — both with passing --self-test
  • docs/android/evidence/security-coverage-2026-10-04/ — §7 (advisory table, fix-presence check)

7. Security coverage on the release track (2026-10-04)

Checked 2026-10-04 against Redoubt 157.0-1 (version.android = 157.0, main at 39d159ca; Beta 4 and Beta 5 were built from this tree). Android moved off ESR on 2026-10-02 (TRACK.md), so this re-asks the question the ESR rebase left open: which Firefox for Android security fixes does the shipped tree lack?

Bottom line: as of 2026-10-04 there is no open gap. All nine Firefox for Android CVEs that were open against the ESR tree are fixed in Firefox 157.0 or earlier, and each fix is in the 157.0 source Redoubt builds. Mozilla has published no Firefox for Android advisory fixed after 157.0.

7.1 Sources and method

  • Advisories. The MFSA index, https://www.mozilla.org/en-US/security/advisories/, fetched 2026-10-04: MFSA 2026-01 to 2026-103. Every Firefox release advisory of 2026 (147 to 157, dot releases included), MFSA 2026-73 and the ESR 153.x advisories (2026-77, -85, -93, -100) were downloaded and parsed per CVE. Each advisory is at https://www.mozilla.org/en-US/security/advisories/mfsa2026-NN/.
  • Android advisories. In 2026 exactly one advisory is titled for Firefox for Android: MFSA 2026-73 (Firefox for Android 153.0.3). None is titled for Firefox Focus for Android. Every other Android fix is a CVE inside a desktop release advisory whose title names "Firefox for Android" or "Firefox Focus for Android". There are 18 of those plus MFSA 2026-73's one, listed in evidence/security-coverage-2026-10-04/android-cves.tsv.
  • Firefox 154-157. MFSA 2026-74 (154, 58 CVEs), 2026-82 (155, 29), 2026-90 (156, 73), 2026-97 (157, 76): 236 CVEs, all "fixed in" a version <= 157.
  • Where each fix lives. The bug's product/component from the Bugzilla REST API where the bug is public, and in every case the fix commit in Mozilla's GitHub mirror (mozilla-firefox/firefox, searched by bug number) and the files it touches.
  • Is it in our tree. Every added line of each fix commit was looked up in the matching file of firefox-157.0.source.tar.xz; every Redoubt patch on the Android list (assets/patches/common.txt + android.txt, 64 patches) was checked for a - line that removes one. Output and caveats: evidence/security-coverage-2026-10-04/fix-presence.txt. This checks source, not a build.

7.2 Closed gaps: the nine CVEs open against the ESR tree

The list is the one in REBASE.md Appendix D §1, "Step 1.3", and it matches the parse above exactly: the Android-titled CVEs fixed after Firefox 153 are these nine and no others.

CVE MFSA fixed in impact bug fix lives in in 157.0 tree Redoubt
CVE-2026-18809 2026-73 Firefox for Android 153.0.3 high 2055683 Gecko (GeckoView, mobile/android/components/geckoview/GeckoViewContentChannelParent.cpp) yes closed
CVE-2026-74951 2026-74 154 moderate 1978587 android-components (feature/sitepermissions, support/utils) + Fenix (ExternalAppBrowserActivity.kt) yes closed
CVE-2026-74975 2026-74 154 low 1842361 android-components (feature/downloads/DownloadsFeature.kt) + Fenix yes closed
CVE-2026-74980 2026-74 154 low 2049034 Fenix (downloads/RenameAndChangeLocationDialogFragment.kt) yes closed
CVE-2026-84117 2026-82 155 high 2053320 Fenix (Nimbus QA tooling moved out of HomeActivity into QANimbusToolingReceiver, guarded by android.permission.DUMP); part 2 is Focus-only yes closed, and stricter (below)
CVE-2026-84127 2026-82 155 moderate 1699444 android-components (engine-gecko GeckoWebExtension.kt, support/webextensions) + Fenix yes closed
CVE-2026-84135 2026-82 155 low 2046661 Firefox Focus for Android only (advisory title) n/a not applicable: Redoubt builds fenix:assemble* only, never focus-android
CVE-2026-92033 2026-90 156 high 2047339 Gecko (ipc/glue/GeckoChildProcessHost.cpp, widget/android/, GeckoView process manager) yes closed
CVE-2026-100823 2026-97 157 low 2054384 android-components (feature/downloads/DownloadNotification.kt, support/ktx) yes closed

Unlinked bugs are security-restricted on Bugzilla; the fix commits are public and named in fix-presence.txt. Bug 2046661 has no public commit, which changes nothing: no Focus code is built.

CVE-2026-84117. Upstream's fix moves Nimbus QA tooling into an exported receiver that only holders of android.permission.DUMP (in practice the adb shell) can reach. Redoubt keeps the receiver and its permission, and patches/android/no-nimbus.patch additionally removes its initializeTooling() call, so on Redoubt the receiver applies no Nimbus command at all. The revert check flags that hunk; it is deliberate.

Who was exposed. The nine were open in Beta 1 to Beta 3 (Beta 3 is 153.4.0esr-1, published 2026-10-02). Beta 4 (157.0-1, 2026-10-03) is the first build that carries them; Beta 5 (2026-10-04) does too.

7.3 The reverse check: ESR fixes missing from 157

Leaving ESR could also lose a fix that only the ESR line got. Every CVE of the four ESR 153.x advisories was matched against the Firefox 147-157 advisories. One is absent from all of them: CVE-2026-100832, high, use-after-free in Graphics: Canvas2D, bug 2072467, listed only in MFSA 2026-100 (ESR 153.4). It is not a gap: the fix (dom/canvas/OffscreenCanvas.cpp) was uplifted to the release branch on 2026-09-21, is an ancestor of the FIREFOX_157_0_RELEASE tag in the GitHub mirror, and its lines are in the 157.0 tarball. No Redoubt patch touches that file. MFSA 2026-97 just does not list it.

7.4 Open gaps

Update 2026-10-14. Since this check: Firefox 157.0.1 (MFSA 2026-104, 2026-10-06) shipped as Redoubt 157.0.1-1 on 2026-10-10; Firefox 158.0 (MFSA 2026-106, 2026-10-13) shipped as Redoubt 158.0-1 on 2026-10-14, followed by 158.0-2 the same day. The next scheduled Firefox release is 2026-10-23 (product-details NEXT_RELEASE_DATE, read 2026-10-14). The bullets below are the 2026-10-04 record.

  • After 157.0: none. As of 2026-10-04 there is no Firefox 157.0.x: https://archive.mozilla.org/pub/firefox/releases/157.0.1/ is a 404, and product-details reports LATEST_FIREFOX_VERSION 157.0 (firefox_versions.json) and Android version 157.0 (mobile_versions.json). No advisory after MFSA 2026-97 covers Firefox or Firefox for Android (2026-98 to -103 are ESR and Thunderbird).
  • Next expected: Firefox 158, NEXT_RELEASE_DATE 2026-10-09 in product-details. Its advisory will open gaps against 157.0-1 until the rebase ships. firefox-release-watch opens the rebase issue (REBASE.md); this section's check should be repeated against each new advisory.
  • Android-only dot releases (watched since 2026-10-04). scripts/firefox-release-watch.py (at 39d159ca) read only LATEST_FIREFOX_VERSION from firefox_versions.json. Mozilla sometimes ships a Firefox for Android dot release that desktop does not get: 153.0.2 exists under pub/fenix/releases/153.0.2/ but has no pub/firefox/releases/153.0.2/source/ tarball (404, checked 2026-10-04), while the security one, 153.0.3 (MFSA 2026-73), had both. Such a dot was not flagged by the watcher, and might have no source tarball to rebase onto (its fix would have to be taken from the release branch). The watcher now also reads mobile_versions.json and opens a Firefox for Android <v> released: rebase Android issue for such a release, noting whether a source tarball exists. The MFSA index stays the check for what the release fixes.
  • Not covered by this section: the platform gaps of §1 to §3 (no content sandbox; DoH rewritten by Fenix on every cold start, with LibreWolf's defaults since Beta 2, row 6) are unchanged. This section is about Mozilla advisories only.

8. Known limitations: passwords and passkeys (2026-10-05, updated 2026-10-14)

These are not security-parity rows. They are listed here because users experience them as limits of Redoubt. Desktop LibreWolf does not have them in the same form: it has its own password manager and no Android Credential Manager. Measured on a 157.0-2 build on an Android 14 x86_64 emulator, with a probe AutofillService and a probe CredentialProviderService. Stock Firefox for Android 157 was run in the same setup for comparison.

  • Password autofill works through any Android autofill service on normal forms. The probe service received the page's username and password fields with web domain and autofill hints from org.redoubtbrowser.
  • Shadow-DOM login forms: fixed in 158.0-1. Reddit's inputs live in open shadow roots (faceplate-text-input). In 157, GeckoViewAutoFillChild only registered fields from the non-composed DOMFormHasPassword / DOMInputPasswordAdded events and from scanDocument's querySelectorAll, and neither reaches into shadow roots; stock Firefox for Android 157 behaves the same. Since 158.0-1, autofill-shadow-dom.patch (LW-M7-42) registers a focused login field in an open shadow root when its form holds a password field. Measured with the probe service (158.0-2 acceptance, row AF): the open-shadow-root login page gets a fill request, closed shadow roots and non-login fields do not. Not yet tested with Bitwarden, KeePassDX or Proton Pass.
  • reddit.com/login does not render on a fresh profile: the page stays blank, while www.reddit.com itself loads. Seen on emulators since 157 and on two phones with the 158.0-2 release (2026-10-14); turning off tracking protection for the site, allowing WebGL, turning off resist-fingerprinting, disabling uBlock Origin or requesting the desktop site did not change it. Under investigation; the autofill fix above could therefore not be tried on Reddit itself.
  • Passkeys need Android 14+ and go through Android Credential Manager. no-gms.patch removes play-services-fido, Gecko's FIDO2 path for older Android, so there is no fallback below Android 14. The probe provider received CallingAppInfo with package org.redoubtbrowser and the page origin set by the browser. Firefox (org.mozilla.firefox) produced the same in the same setup.
  • Some managers do not accept Redoubt as a browser for passkeys. A provider that checks browsers against an allowlist rejects Redoubt until it is on that list. Proton Pass ships a copy of Google Password Manager's list and offers no manual override, so neither offers passkeys to Redoubt. KeePassDX lets the user add Redoubt (Settings > Form filling > Passkeys settings > Privileged apps, or the "App not recognized" prompt on first use; PasskeysPrivilegedAppsPreferenceDialogFragmentCompat, KeePassDX 4.5.5). Bitwarden offers Trust on its "Unrecognized browser" prompt (TrustPrivilegedAddPrompt, since PM-19107). Adding Redoubt to Bitwarden's and KeePassDX's community lists, and asking Proton to add it, is planned; no request had been filed by 2026-10-14. The KeePassDX and Bitwarden steps come from their source and are PENDING a device test with Redoubt.
  • Conditional-mediation passkeys (autofill-style suggestions in the username field) are unavailable. PublicKeyCredential:: IsConditionalMediationAvailable resolves false under MOZ_WIDGET_ANDROID (dom/webauthn/PublicKeyCredential.cpp), so every Firefox-based Android browser has this limit. Sites' explicit passkey buttons (modal WebAuthn) are not affected.