03.02.2026

Bubblewrap Sandboxing Guide: Lightweight Process Isolation on Linux

head-image

When you need to run untrusted code or isolate applications without spinning up full containers, bubblewrap offers an elegant solution. Used by Flatpak and other major projects, bubblewrap provides unprivileged sandboxing using Linux kernel namespaces. This guide covers everything you need to know to start sandboxing processes effectively.

What is Bubblewrap?

Bubblewrap (bwrap) is a low-level sandboxing tool that creates isolated environments using Linux kernel features like namespaces and seccomp filters. Unlike Docker or systemd-nspawn, bubblewrap is designed for unprivileged users and focuses on minimal attack surface.

Key characteristics:

  • Unprivileged operation: No root access required (uses user namespaces)
  • Minimal footprint: Small, auditable codebase
  • Flexible isolation: Fine-grained control over what the sandbox can access
  • No daemon: Runs as a simple command wrapper

Why Use Bubblewrap Over Docker?

Feature Bubblewrap Docker
Root required No Yes (or rootless mode)
Daemon process No Yes
Image management No Yes
Startup time Instant Seconds
Resource overhead Minimal Higher
Use case Process isolation Full containerization

Choose bubblewrap when you need:

  • Quick process isolation without infrastructure
  • To sandbox a single command or script
  • Minimal overhead for development workflows
  • Unprivileged sandboxing on shared systems

Installation

Ubuntu/Debian:

sudo apt install bubblewrap

Fedora/RHEL/CentOS:

sudo dnf install bubblewrap

Arch Linux:

sudo pacman -S bubblewrap

From source:

git clone https://github.com/containers/bubblewrap.git
cd bubblewrap
meson _builddir
meson compile -C _builddir
sudo meson install -C _builddir

Verify installation:

bwrap --version

Basic Usage

The simplest bubblewrap invocation creates an isolated environment with access to system binaries:

bwrap \
  --ro-bind /usr /usr \
  --symlink usr/lib64 /lib64 \
  --symlink usr/bin /bin \
  --proc /proc \
  --dev /dev \
  --unshare-pid \
  bash

This creates a sandbox where:

  • /usr is mounted read-only
  • /proc and /dev are properly set up
  • PID namespace is isolated (processes inside can't see host processes)
  • A bash shell runs inside the sandbox

Understanding Bubblewrap Options

Filesystem Mounts

--ro-bind /source /dest    # Read-only bind mount
--bind /source /dest       # Read-write bind mount
--dev-bind /source /dest   # Bind mount preserving device nodes
--tmpfs /path              # Mount tmpfs at path
--dir /path                # Create empty directory
--symlink target /link     # Create symbolic link
--file FD /path            # Create file from file descriptor

Namespace Isolation

--unshare-user             # Create new user namespace
--unshare-pid              # Create new PID namespace
--unshare-net              # Create new network namespace (no network)
--unshare-ipc              # Create new IPC namespace
--unshare-uts              # Create new UTS namespace (hostname)
--unshare-cgroup           # Create new cgroup namespace

Security Options

--new-session              # Create new terminal session
--die-with-parent          # Kill sandbox when parent dies
--as-pid-1                 # Run as PID 1 inside sandbox
--cap-drop ALL             # Drop all capabilities
--seccomp FD               # Apply seccomp filter from file descriptor

Practical Examples

Sandbox an Untrusted Script

Run a downloaded script with minimal filesystem access:

bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --symlink usr/bin /bin \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --unshare-all \
  --new-session \
  --die-with-parent \
  /bin/bash ./untrusted-script.sh

Isolated Development Environment

Create a sandbox with access to your project directory:

bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --ro-bind /etc/resolv.conf /etc/resolv.conf \
  --ro-bind /etc/ssl /etc/ssl \
  --symlink usr/bin /bin \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --bind "$PWD" "$PWD" \
  --chdir "$PWD" \
  --unshare-pid \
  --new-session \
  bash

This gives you:

  • Read-only access to system files
  • Network access (DNS resolution works)
  • Read-write access to current directory only
  • Isolated PID namespace

Network-Isolated Sandbox

For complete network isolation:

bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --symlink usr/bin /bin \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --unshare-net \
  --new-session \
  bash

Inside this sandbox, only loopback (127.0.0.1) is available. Perfect for testing applications that shouldn't have network access.

Sandbox with Custom Home Directory

Isolate an application from your real home directory:

mkdir -p /tmp/fake-home

bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --symlink usr/bin /bin \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --bind /tmp/fake-home "$HOME" \
  --setenv HOME "$HOME" \
  --unshare-pid \
  --new-session \
  bash

Sandboxing GUI Applications

For GUI apps, you need to expose X11 or Wayland sockets:

# X11
bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --symlink usr/bin /bin \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --ro-bind /etc/fonts /etc/fonts \
  --ro-bind ~/.Xauthority ~/.Xauthority \
  --bind /tmp/.X11-unix /tmp/.X11-unix \
  --setenv DISPLAY "$DISPLAY" \
  --new-session \
  firefox

Creating Reusable Sandbox Scripts

For complex sandboxes, create wrapper scripts:

#!/bin/bash
# sandbox-dev.sh - Development sandbox

exec bwrap \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --ro-bind /etc/resolv.conf /etc/resolv.conf \
  --ro-bind /etc/ssl /etc/ssl \
  --ro-bind /etc/hosts /etc/hosts \
  --ro-bind /etc/localtime /etc/localtime \
  --ro-bind /etc/passwd /etc/passwd \
  --ro-bind /etc/group /etc/group \
  --symlink usr/bin /bin \
  --symlink usr/sbin /sbin \
  --proc /proc \
  --dev /dev \
  --tmpfs /tmp \
  --tmpfs /run \
  --bind "$PWD" "$PWD" \
  --chdir "$PWD" \
  --unshare-pid \
  --unshare-uts \
  --hostname sandbox \
  --new-session \
  --die-with-parent \
  "$@"

Usage:

chmod +x sandbox-dev.sh
./sandbox-dev.sh bash
./sandbox-dev.sh python3 script.py
./sandbox-dev.sh npm install

Debugging Sandbox Issues

When your sandboxed application fails, use strace to identify missing dependencies:

strace -e trace=open,openat,stat,access -f bwrap \
  --ro-bind /usr /usr \
  ... \
  your-command 2>&1 | grep -E "ENOENT|EACCES"

This shows which files the application tried to access but couldn't find.

Common issues:

  • DNS not working: Bind mount /etc/resolv.conf
  • SSL certificates missing: Bind mount /etc/ssl and /usr/share/ca-certificates
  • Timezone wrong: Bind mount /etc/localtime
  • Dynamic libraries missing: Check ldd your-binary and bind required paths

Security Considerations

Bubblewrap provides defense in depth, but understand its limitations:

What bubblewrap protects against:

  • Filesystem access outside bind mounts
  • Process visibility (with PID namespace)
  • Network access (with network namespace)
  • IPC between sandboxed and host processes

What bubblewrap does NOT protect against:

  • Kernel exploits (sandbox shares the kernel)
  • Side-channel attacks
  • Data exfiltration through allowed network access
  • Covert channels through shared resources

For higher security requirements, combine bubblewrap with:

  • Seccomp filters to restrict syscalls
  • SELinux/AppArmor policies
  • Resource limits via cgroups
  • Network filtering with iptables/nftables

Comparison with Alternatives

Bubblewrap vs Firejail

Firejail includes many pre-built profiles for common applications but has a larger attack surface. Bubblewrap is more minimal and requires manual configuration.

Bubblewrap vs systemd-nspawn

systemd-nspawn is designed for full system containers and requires root. Bubblewrap targets lightweight, unprivileged process sandboxing.

Bubblewrap vs Docker

Docker provides complete container lifecycle management with images, networking, and orchestration. Bubblewrap is simpler, faster, and runs without a daemon.

Real-World Use Cases

  • Flatpak: Uses bubblewrap to sandbox desktop applications
  • GNOME: Sandboxes document viewers and other apps
  • CI/CD: Isolate build processes without full containers
  • Development: Run untrusted code or AI coding agents safely
  • Testing: Isolate test environments from the host system

Conclusion

Bubblewrap fills an important gap between running processes directly and full containerization. Its minimal design, unprivileged operation, and fine-grained control make it ideal for lightweight sandboxing scenarios. Whether you're isolating development environments, running untrusted scripts, or building secure application launchers, bubblewrap provides the tools you need. For comprehensive infrastructure monitoring and incident management when running sandboxed workloads in production, consider Akmatori, an open-source AI agent platform that helps SRE teams respond to infrastructure incidents faster.

FAQ

  • Can bubblewrap run as a non-root user?

    • Yes, that's its primary design goal. It uses user namespaces to provide sandboxing without root privileges.
  • Is bubblewrap as secure as a VM?

    • No. Bubblewrap shares the host kernel, so kernel exploits could escape the sandbox. VMs provide stronger isolation.
  • Can I use bubblewrap on systems without user namespace support?

    • Yes, bubblewrap can be installed setuid root as a fallback, though this is less common on modern systems.
  • How do I persist changes made inside the sandbox?

    • Use --bind instead of --ro-bind for directories where you want to save changes. Changes to --bind mounts persist to the host.
  • Can bubblewrap limit CPU or memory usage?

    • Not directly. Use cgroups (via systemd-run or manual configuration) alongside bubblewrap for resource limits.

Automate incident response and prevent on-call burnout with AI-driven agents!