Contents

Firejail vs Bubblewrap: Which Linux Sandbox Should You Use?

Firejail and Bubblewrap are the two leading lightweight sandboxing tools for Linux, and they take very different approaches to the same problem. Firejail is a feature-rich, SUID-root sandbox shipping over 1,000 pre-built application profiles that work out of the box for browsers, messaging apps, media players, and more. Bubblewrap (bwrap) is a minimal, unprivileged namespace tool - the same one Flatpak uses internally - that gives you precise control over exactly what a sandboxed process can see, at the cost of requiring you to build the sandbox yourself. If you want quick desktop app isolation with sensible defaults, pick Firejail. If you need a minimal, auditable sandbox with no SUID binary and complete control over every mount point and capability, pick Bubblewrap.

Why Sandbox Desktop Applications at All?

Every process running under your Linux user account inherits your full permissions. That means any application - a browser, a chat client, a random Electron app - can read ~/.ssh/, ~/.gnupg/, your browser cookies, your password manager database, and every document in your home directory. There is no permission boundary between programs running as the same user.

This is not a theoretical concern. Supply chain attacks through npm and PyPI packages have become routine. Browser zero-days still appear regularly. Electron apps like Discord, Zoom, and Slack access clipboard contents and filesystem paths well beyond what their stated purpose requires. A single compromised application or malicious browser extension gets access to everything your user account can touch.

Sandboxing restricts what an application can see and do:

  • Filesystem visibility: hide sensitive directories like ~/.ssh, ~/.gnupg, and ~/.config from applications that have no business reading them
  • Network access: block network entirely or restrict it to specific protocols
  • IPC isolation: prevent X11 keylogging, a real risk under Xorg where any application can capture keystrokes from any other
  • Device access: block webcam and microphone unless explicitly granted
  • System call filtering: seccomp-bpf filters restrict which kernel interfaces the process can use

The same seccomp-bpf and capability-dropping techniques apply to hardening container images โ€” the defense-in-depth principles translate directly between namespace-based sandboxes and Docker containers.

Flatpak and Snap already provide sandboxing, but not every application ships as a Flatpak, and many Flatpak packages request --filesystem=home, which defeats much of the purpose. Firejail and Bubblewrap let you sandbox any native package installed through your distribution’s package manager.

Wayland’s protocol provides per-surface isolation by default - no application can capture another’s input or output. But Xwayland, which many legacy apps still require, breaks this isolation. Sandboxing fills the gap for those applications.

Sandboxing is not a substitute for keeping software updated. It is a defense-in-depth layer that limits the damage when prevention fails.

Firejail - Feature-Rich Sandboxing with Pre-Built Profiles

Firejail is the more approachable of the two tools. Install it, type firejail firefox, and your browser launches inside a sandbox with a curated set of restrictions drawn from Firefox’s built-in security profile. The current stable version is 0.9.80, with the 0.9.74 release (March 2025) having introduced experimental Landlock LSM support for kernel-level filesystem access 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 isolate the process
  2. Applies seccomp-bpf syscall filters to restrict available kernel interfaces
  3. Mounts a restricted filesystem view based on the application’s profile
  4. Drops all elevated privileges
  5. Executes the target application inside the sandbox

The SUID-root design means Firejail works on any Linux system regardless of whether unprivileged user namespaces are enabled. This is both its strength and its primary criticism (more on that 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 temporary, empty home directory that gets discarded on exit:

firejail --private discord

See what restrictions a profile applies:

firejail --debug firefox

Key Profile Directives

Firejail profiles use a declarative syntax to define restrictions:

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 modify a profile, copy it to your user config directory:

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

Edit the copy to add or remove restrictions. Your user-level profile takes precedence over the system one.

Desktop Integration

Running sudo firecfg rewrites symlinks in /usr/local/bin/ so that every profiled application launched from your desktop menu, dmenu, or rofi automatically runs through Firejail. This is the easiest way to sandbox your entire 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 emergency fix for a GTK compatibility issue: applications using glycin 2.0.0 or later via gdk-pixbuf2 (Firefox, Thunderbird, GIMP) were crashing inside Firejail sandboxes. The fix replaced bubblewrap calls within the sandbox with a dummy fbwrap program. A --allow-bwrap flag was added for cases where the real bwrap is needed.

Bubblewrap - Minimal Unprivileged Namespace Sandboxing

Bubblewrap takes the opposite approach from Firejail. It is a minimal, low-level tool for constructing Linux namespaces without requiring SUID-root. You build the sandbox mount by mount, specifying exactly which directories the process can see and whether they are read-only or writable. This gives maximum control and auditability at the cost of significantly more effort per application.

The current 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 uses clone() with CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, and related flags to create unprivileged user namespaces . On most modern distributions (Ubuntu 24.04+, Fedora 40+, Arch), kernel.unprivileged_userns_clone is enabled by default, so bwrap runs without any SUID binary. This smaller trusted computing base is one of its primary advantages.

Basic Sandbox Example

Launch Firefox with a minimal root filesystem and an empty home directory:

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 creates a read-only view of the system libraries, an empty home directory, and shares the host network (since 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 external connectivity. Use --share-net to keep host networking. Unlike Firejail, there is no built-in support for network bridges, bandwidth limits, or DNS filtering - it is strictly all-or-nothing.

Wrapper Scripts

Since bwrap commands are verbose, the standard approach is to write shell wrapper scripts. 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 writing raw bwrap commands feels tedious, Bubblejail provides a Firejail-like experience on top of Bubblewrap. It offers a GUI for managing sandboxed instances, with each instance getting its own separate home directory. Profiles are configured through a services.toml file that defines which system resources (PulseAudio, GPU, network) the sandbox can access.

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 compared to Firejail’s 1,000+, but it covers the most common desktop applications.

Head-to-Head Comparison

Choosing between these tools depends on your threat model, technical comfort, and how much time you want to invest in configuration.

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 been the source of real security incidents. CVE-2022-31214 was a privilege escalation vulnerability in Firejail’s join.c that allowed local attackers to craft a bogus Firejail container, trick the SUID-root binary into joining it, and escape to full root access. The vulnerability affected versions before 0.9.68 and was patched, but it illustrates the fundamental tension: a security tool with root privileges becomes an attractive attack target itself.

Bubblewrap avoids this entirely by operating within unprivileged user namespaces. There is no privileged binary to exploit. The trade-off is that bwrap requires the kernel to have unprivileged user namespaces enabled, which is the default on most distributions since 2024 but can be disabled by administrators.

When to Pick Which

Choose Firejail when:

  • You want to sandbox many desktop applications with minimal effort
  • You need network filtering, DNS overrides, or bandwidth controls per application
  • You are on a system without unprivileged user namespaces
  • You want the firecfg auto-sandbox feature for your entire desktop

Choose Bubblewrap when:

  • SUID-root binaries are unacceptable in your threat model
  • You need to audit every aspect of the sandbox configuration
  • You are sandboxing a small number of specific applications and can invest time per app
  • You already use Flatpak and want to understand or customize its underlying sandbox

Practical Sandboxing Recipes

Firefox with Firejail

Allow only Downloads and the Firefox profile directory:

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 persistent home directory, separate from your real one:

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

Analyzing an Untrusted Binary

Run a suspicious binary with no network, no home directory, and automatic 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 ensures the sandboxed process is killed if your terminal session exits. The same pattern underpins local AI code interpreter agents that need to execute untrusted LLM-generated code in an ephemeral sandbox.

VS Code with Restricted Filesystem

Restrict VS Code to only see your Projects and Downloads directories:

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

Note that VS Code’s integrated terminal inherits these sandbox restrictions, so shell commands inside VS Code are also confined.

Browser Profile Isolation

Run separate browser instances for different activities, each with its own isolated 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 instance gets its own cookies, history, and extensions with no cross-access.

Steam with Restricted Access

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

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

Full GPU and network access is preserved since games need both.

Beyond Firejail and Bubblewrap

A few related technologies overlap with or complement these tools:

Landlock is a kernel-level LSM that allows unprivileged processes to restrict their own filesystem access. Landrun is a standalone tool built on Landlock that provides Firejail-like usability without SUID. Firejail 0.9.74+ can use Landlock as an additional restriction layer via the --landlock flag.

Landrun sandboxing a process with Landlock - no root required

For system services rather than desktop apps, systemd offers its own sandboxing directives: DynamicUser=, ProtectHome=, PrivateNetwork=, and similar options that provide isolation without any extra tools.

AppArmor and SELinux are Mandatory Access Control frameworks that enforce restrictions at the kernel level, independent of namespaces. Both can be layered on top of Firejail or Bubblewrap.

The xdg-desktop-portal system provides controlled access to host resources (file picker, screen sharing, printing) through D-Bus interfaces, allowing sandboxed apps to request specific permissions on demand rather than getting blanket filesystem access.

For most desktop Linux users, Firejail’s profile library and ease of use make it the practical starting point. If the SUID-root model concerns you, Bubblejail offers a middle ground between Firejail’s convenience and Bubblewrap’s minimal trusted computing base. And for the security-conscious willing to invest time per application, raw Bubblewrap commands give you the tightest possible sandbox with full auditability.