Contents

Firejail vs Bubblewrap: Which Linux Sandbox Should You Use?

Firejail and Bubblewrap are the two top lightweight sandbox tools for Linux. They take very different paths to the same job. Firejail is a SUID-root sandbox with over 1,000 ready-made profiles. It works out of the box for browsers, chat apps, and media players. Bubblewrap (bwrap) is a small, unprivileged namespace tool. It’s the same one Flatpak uses inside. You get exact control over what a sandboxed app can see, but you build the sandbox yourself. Want quick desktop isolation with sane defaults? Pick Firejail. Need a tight, auditable sandbox with no SUID binary? Pick Bubblewrap.

Why Sandbox Desktop Applications at All?

Every process under your Linux user account inherits your full rights. So any app, a browser, a chat client, a random Electron tool, can read ~/.ssh/, ~/.gnupg/, your browser cookies, your password manager, and every file in your home folder. There’s no permission wall between programs run as the same user.

This isn’t a theory. Supply chain attacks via npm and PyPI packages happen all the time. Browser zero-days still show up. Electron apps like Discord, Zoom, and Slack reach into clipboard contents and file paths far past their stated job. One hacked app or shady browser extension gets access to everything your user account can touch.

Sandboxing restricts what an application can see and do:

  • Filesystem view: hide folders like ~/.ssh, ~/.gnupg, and ~/.config from apps that have no need to read them
  • Network access: block the network or limit it to set protocols
  • IPC isolation: stop X11 keylogging, a real risk under Xorg where any app can grab keystrokes from any other
  • Device access: block webcam and microphone unless granted
  • Syscall filtering: seccomp-bpf filters limit which kernel calls the process can use

The same seccomp-bpf and capability-dropping tricks apply to hardening container images . Defense in depth maps directly between namespace sandboxes and Docker.

Flatpak and Snap already sandbox apps. Still, not every app ships as a Flatpak, and many Flatpak packages ask for --filesystem=home, which guts the point. Firejail and Bubblewrap let you sandbox any native package from your distro’s package manager.

Wayland’s protocol gives per-surface isolation by default: no app can grab another’s input or output. But Xwayland, which many legacy apps still need, breaks that wall. Sandboxing fills the gap.

Sandboxing complements patched software rather than replacing it. When prevention fails, the blast radius stays inside the sandbox instead of spreading across your home folder.

Firejail: Feature-Rich Sandboxing with Pre-Built Profiles

Firejail is the friendlier of the two. Install it, type firejail firefox, and your browser starts inside a sandbox with a curated rule set drawn from Firefox’s built-in profile. The stable version is 0.9.80. The 0.9.74 release (March 2025) added test-grade Landlock LSM support for kernel-level filesystem control.

Installation

On Debian 13+ or Ubuntu 24.04+:

sudo apt install firejail firejail-profiles

On Fedora 41+:

sudo dnf install firejail

Verify with firejail --version. You should see 0.9.74 or later.

How It Works

Firejail is a SUID-root binary. When you run firejail firefox, it:

  1. Creates Linux namespaces (mount, PID, network, UTS) to wall off the process
  2. Applies seccomp-bpf syscall filters to limit kernel calls
  3. Mounts a trimmed filesystem view from the app’s profile
  4. Drops all root rights
  5. Runs the target app inside the sandbox

The SUID-root design means Firejail works on any Linux box, even when unprivileged user namespaces are off. That’s both its main strength and its main critique (more on this in the comparison section).

Firejail sandboxed home directory as seen by a browser process
The restricted filesystem view inside a Firejail sandbox
Image: Firejail

Basic Usage

Launch Firefox with its default sandbox profile:

firejail firefox

Launch Discord with a throwaway empty home folder, wiped on exit:

firejail --private discord

See what restrictions a profile applies:

firejail --debug firefox

Key Profile Directives

Firejail profiles use a plain syntax to spell out limits:

DirectiveEffect
whitelist ~/DownloadsOnly expose the Downloads directory
blacklist ~/.sshHide SSH keys from the sandboxed app
net noneDisable all network access
protocol unix,inet,inet6Restrict allowed socket types
seccompEnable default syscall filter
caps.drop allDrop all Linux capabilities
norootPrevent SUID binaries inside the sandbox
--landlockEnable Landlock filesystem restrictions (0.9.74+)

Customizing Profiles

To tweak a profile, copy it to your user config folder:

cp /etc/firejail/firefox.profile ~/.config/firejail/firefox.profile

Edit the copy to add or drop rules. Your user profile wins over the system one.

Desktop Integration

Running sudo firecfg rewrites symlinks in /usr/local/bin/. After that, every profiled app you launch from your desktop menu, dmenu, or rofi runs through Firejail. It’s the easiest way to sandbox your whole desktop without changing habits.

Firetools graphical interface for managing Firejail sandboxes
Firetools provides a graphical sandbox manager and launcher
Image: Firejail

Recent Notable Changes

The 0.9.78 release (January 2026) was an urgent GTK fix. Apps using glycin 2.0.0 or later via gdk-pixbuf2 (Firefox, Thunderbird, GIMP) crashed inside Firejail sandboxes. The fix swapped bubblewrap calls in the sandbox for a stub fbwrap program. A new --allow-bwrap flag covers the cases where real bwrap is needed.

Bubblewrap: Minimal Unprivileged Namespace Sandboxing

Bubblewrap goes the other way. It’s a small, low-level tool for building Linux namespaces without SUID-root. You build the sandbox mount by mount, spelling out which folders the process can see and whether each one is read-only or writable. You get full control and easy audit, but you also pay in time per app.

The stable version is 0.11.1.

Installation

On Debian 13+ or Ubuntu 24.04+:

sudo apt install bubblewrap

On Fedora 41+:

sudo dnf install bubblewrap

Verify with bwrap --version.

How It Works

Bubblewrap calls clone() with CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, and related flags to spawn unprivileged user namespaces . On most modern distros (Ubuntu 24.04+, Fedora 40+, Arch), kernel.unprivileged_userns_clone is on by default, so bwrap runs with no SUID binary. That smaller trust base is one of its main wins.

Basic Sandbox Example

Launch Firefox with a tiny root filesystem and an empty home folder:

bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --ro-bind /etc/fonts /etc/fonts \
  --ro-bind /etc/resolv.conf /etc/resolv.conf \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --tmpfs /home \
  --unshare-all \
  --share-net \
  --new-session \
  -- /usr/bin/firefox

This sets up a read-only view of the system libs, an empty home, and a shared host network (Firefox needs it). Everything else is hidden.

Mount Types

FlagEffect
--bind src destRead-write bind mount
--ro-bind src destRead-only bind mount
--tmpfs pathEphemeral tmpfs (contents lost on exit)
--dev-bind src destDevice access (for GPU, etc.)
--symlink src destCreate a symlink for FHS compatibility
--unshare-netLoopback-only network namespace
--share-netKeep host networking
--die-with-parentKill sandboxed process when parent exits

Network Isolation

Adding --unshare-net gives the process a loopback-only network namespace with no outside link. Use --share-net to keep host networking. Unlike Firejail, there’s no built-in support for bridges, bandwidth caps, or DNS filtering. It’s strictly all-or-nothing.

Wrapper Scripts

Bwrap commands run long, so the standard fix is a shell wrapper script. For example, ~/bin/sandboxed-firefox.sh:

#!/bin/bash
exec bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --ro-bind /etc/fonts /etc/fonts \
  --ro-bind /etc/resolv.conf /etc/resolv.conf \
  --bind ~/.mozilla ~/.mozilla \
  --bind ~/Downloads ~/Downloads \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --unshare-all \
  --share-net \
  --new-session \
  -- /usr/bin/firefox "$@"

Bubblejail: A Higher-Level Frontend

If raw bwrap commands feel tedious, Bubblejail sits on top of Bubblewrap with a Firejail-like feel. It has a GUI for managing sandboxed instances, and each one gets its own home folder. You set up profiles through a services.toml file. It lists which host parts (PulseAudio, GPU, network) the sandbox can reach.

Bubblejail configuration GUI showing sandbox instance settings
Bubblejail provides a graphical interface for configuring Bubblewrap sandboxes
Image: Bubblejail

Create a sandboxed Firefox instance:

bubblejail create --profile firefox FirefoxInstance

Bubblejail ships about 50 pre-built profiles versus Firejail’s 1,000+. Still, it covers the most common desktop apps.

Head-to-Head Comparison

The right pick depends on your threat model, your comfort with config, and how much time you want to spend tuning.

DimensionFirejailBubblewrap
Setup effortfirejail app-name works immediatelyManual mount construction required
Profile ecosystem1,000+ upstream profilesNone built-in (Bubblejail has ~50)
SUID requirementYes (SUID-root binary)No (unprivileged namespaces)
Attack surfaceLarger (SUID binary has had CVEs)Smaller (no privileged binary)
Network sandboxingPer-app bridges, bandwidth limits, DNS filteringAll-or-nothing namespace isolation
D-Bus filteringBuilt-in proxy supportRequires external xdg-dbus-proxy
Landlock supportExperimental (0.9.74+)Not applicable (use with other tools)
Performance overheadNegligible (~5ms namespace setup)Negligible (~5ms namespace setup)
Desktop integrationfirecfg auto-sandboxes all profiled appsManual (wrapper scripts or Bubblejail)

The SUID Question

Firejail’s SUID-root binary has caused real security bugs. CVE-2022-31214 was a privilege-escalation flaw in Firejail’s join.c. Local attackers could craft a fake Firejail container, trick the SUID-root binary into joining it, and break out to full root. The bug hit versions before 0.9.68 and got patched. Still, it shows the core tension: a security tool with root rights turns into a juicy target itself.

Bubblewrap sidesteps this by running inside unprivileged user namespaces. There’s no privileged binary to attack. The trade-off: bwrap needs the kernel to have unprivileged user namespaces on. That’s the default on most distros since 2024, but admins can turn it off.

When to Pick Which

Choose Firejail when:

  • You want to sandbox many desktop apps with little effort
  • You need network filtering, DNS overrides, or bandwidth caps per app
  • You’re on a system without unprivileged user namespaces
  • You want the firecfg auto-sandbox for your whole desktop

Choose Bubblewrap when:

  • SUID-root binaries are off the table in your threat model
  • You need to audit every part of the sandbox config
  • You’re sandboxing a small set of specific apps and can spend time per app
  • You already use Flatpak and want to learn or tweak its built-in sandbox

Practical Sandboxing Recipes

Firefox with Firejail

Allow only Downloads and the Firefox profile folder:

firejail --whitelist=~/Downloads --whitelist=~/.mozilla firefox

Add DNS override for privacy:

firejail --whitelist=~/Downloads --whitelist=~/.mozilla --dns=9.9.9.9 firefox

Discord with an Isolated Home

Give Discord its own home folder, kept apart from your real one:

firejail --private=~/.sandboxes/discord discord

Analyzing an Untrusted Binary

Run a shady binary with no network, no home folder, and auto cleanup:

bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --tmpfs /home \
  --unshare-all \
  --new-session \
  --die-with-parent \
  -- ./suspicious-binary

The --die-with-parent flag kills the sandboxed process when your terminal session exits, cleaning up resources automatically. This pattern is essential for running untrusted code in throwaway sandboxes.

VS Code with Restricted Filesystem

Limit VS Code to only your Projects and Downloads folders:

firejail --whitelist=~/Projects --whitelist=~/Downloads --seccomp code

VS Code’s built-in terminal inherits the same sandbox rules, so shell commands inside VS Code are confined too.

Browser Profile Isolation

Run separate browser instances for separate tasks, each with its own storage:

# Banking browser, no access to other profiles
firejail --private=~/.sandboxes/browser-banking firefox --no-remote

# Social media browser
firejail --private=~/.sandboxes/browser-social firefox --no-remote

# General browsing
firejail --private=~/.sandboxes/browser-general firefox --no-remote

Each one keeps its own cookies, history, and extensions with no cross-access.

Steam with Restricted Access

Stop Steam from reading your documents, SSH keys, or browser data:

firejail --whitelist=~/.local/share/Steam --whitelist=~/Games steam

Full GPU and network access stays in place since games need both.

Beyond Firejail and Bubblewrap

A few related tools overlap with or pair well with these two:

Landlock is a kernel-level LSM. It lets a process cap its own filesystem access with no root rights. Landrun is a standalone tool on top of Landlock that feels like Firejail with no SUID. Firejail 0.9.74+ can use Landlock as an extra layer via the --landlock flag.

Landrun sandboxing a process with Landlock, no root required

For system services rather than desktop apps, systemd has its own sandbox knobs: DynamicUser=, ProtectHome=, PrivateNetwork=, and similar flags. They give you isolation with no extra tools.

AppArmor and SELinux are MAC systems. They push rules at the kernel level, apart from namespaces. Both stack cleanly on top of Firejail or Bubblewrap.

The xdg-desktop-portal system gives gated access to host parts like the file picker, screen sharing, and printing through D-Bus. Sandboxed apps ask for set rights on demand rather than getting blanket filesystem access.

For most desktop Linux users, Firejail’s profile library and easy on-ramp make it the practical start. If the SUID-root model worries you, Bubblejail sits between Firejail’s ease and Bubblewrap’s small trust base. And for the security-minded who can spend time per app, raw Bubblewrap gives you the tightest sandbox with a full audit trail.