Build1 publisher3 min readPublished
A stale whitelist path in firejail's Firefox profile strips the sandbox of its extensions
The packaged firejail profile allows a Mozilla directory that Firefox stopped using at version 150, so a jail that looks hardened opens a fresh empty browser every launch, ad blocker included in the loss.
The Engineer · Build desk

What happened
- The stock /etc/firejail/firefox.profile whitelists only the legacy locations, ${HOME}/.mozilla and ${HOME}/.cache/mozilla/firefox, and a firejail whitelist hides any path it does not name.
- About 50 stale *.default cache directories under ~/.cache/mozilla/firefox were the fingerprint of a fresh profile per launch, with the author's extensions and logins never present.
- The working setup keeps one persistent sandbox profile and forces permanent private browsing via user.js, with a narrow whitelist pinned in ~/.config/firejail/firefox.local.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint The failure produces no launch-time signal, so a jail can run about fifty sessions of deliberately risky browsing before anyone notices the ad blocker never loaded.
- exposure The netfilter rules meant to keep the sandbox off the LAN were never applied, and the tool reported nothing, so the network half of the isolation sat open while it looked configured.
- decision Fixing the path forces a choice: open all of ~/.config/mozilla and let the jail read the main profile, or pin one profile directory in a per-user override.
- cost Connectivity checks for a jailed browser have to resolve a name, because a clean TCP handshake to an address passes while DNS is broken.
Firefox does not fail when its profile root is missing. It creates a new profile and carries on. The window opens, pages load, and the browser, in the writeup's words, "only seems to use its own default profile" [4].
Two lines in the packaged profile cause it: `whitelist ${HOME}/.mozilla` and `whitelist ${HOME}/.cache/mozilla/firefox` [2]. A firejail whitelist is an allow-list mount: it hides every path it does not name, and `~/.config/mozilla` is where Firefox 150 and later keep profiles [1][3].
About 50 stale `*.default` cache directories under `~/.cache/mozilla/firefox/` recorded the result [5]. At one directory per session, that is roughly fifty launches [23], none of them with uBlock Origin loaded [7].
Whitelisting all of `~/.config/mozilla` clears the symptom and breaks the requirement. `ggh3azgx.default-release` becomes readable from inside the jail [9], and the sandbox exists so that the dirty profile cannot read the real one [8].
Attempt two copied a config template into a fresh session directory on each launch and ran `firejail --private=<dir>`, which never mounts the real home [10]. Firefox's profile-lock files came along in the copy. The next launch read them as a crash and opened Troubleshoot Mode with extensions disabled [11].
What shipped keeps one persistent sandbox profile and forces `browser.privatebrowsing.autostart=true` through `user.js`, so the configuration persists and the activity does not [12]. Three files carry it. `~/.config/firejail/firefox.local` holds the narrow whitelist and survives the package updates that replace the copy in `/etc` [13]. The profile's `user.js` re-applies private browsing and the anti-fingerprinting prefs at every startup [14]. `~/.local/bin/fsand` refuses to run when the profile is already open, clears stale locks, then calls `firejail firefox -profile <sandbox> -no-remote` [15]. That is `-profile` with a path and not `-P` with a name, because the tight whitelist hides `profiles.ini`, leaving `-P` nothing to resolve [16].
Network isolation failed the same way, without a message. The packaged `/etc/firejail/firejail.config` sets `restricted-network yes`, which means firejail creates no network namespace, so the sandbox shares the host stack and can reach the router admin page at 192.168.29.1 along with the rest of the LAN [17]. The netfilter ruleset meant to prevent that was not applied [18]. Switching the setting to `no` gave the sandbox a virtual NIC on the only bridge on the machine, `lxcbr0`, an LXC leftover on 10.0.3.1/24, with the sandbox at 10.0.3.200 [19].
An hour then went into a wrong conclusion. Raw TCP to 1.1.1.1:443 worked, so the network looked fine; an IP handshake does not exercise DNS, and the browser resolves a name for every link [20]. The iptables rules ended up idempotent, `iptables -C ... || iptables -A ...` inside `/usr/local/sbin/firejail-net-setup.sh`, held by a systemd oneshot [21]. The inline `||` failed first: systemd does not run shell operators in `ExecStart`, so the rules have to live in a real bash script that systemd calls [22].
One laptop is the whole sample here: Pop!_OS 24.04, Firefox 152, firejail 0.9.72 [6]. The writeup does not list which other distributions ship those same two whitelist lines. For anyone running a firejail browser jail on Firefox 150 or later, the cheap check is the count of `*.default` directories under `~/.cache/mozilla/firefox/` [5].
What to watch
- Whether firejail ships an updated firefox.profile whitelisting ~/.config/mozilla, which would make the per-user firefox.local override unnecessary.
- Whether distributions patch the packaged profile before Firefox 150 or later lands in their stable repositories.
- Whether other Mozilla-related firejail profiles reference the legacy ~/.mozilla path and fail the same silent way.