Jump to content

Claude Code Isolation and Burner Workflow 260211: Difference between revisions

From Game in the Brain Wiki
Remove BoxBuddy; add True Filesystem Isolation section with isolated distrobox commands
Add HOST/DISTROBOX labels, golden image workflow, cloning commands
Line 9: Line 9:


This protects against malicious prompt injection by limiting what Claude Code can access, even if it is tricked into running harmful commands.
This protects against malicious prompt injection by limiting what Claude Code can access, even if it is tricked into running harmful commands.
== Command Context ==
Every command in this guide is prefixed with where it must be run:
{| class="wikitable"
|-
! Prefix !! Meaning
|-
| <code>'''[HOST]'''</code> || Run this in a terminal on your normal Linux desktop, outside any container
|-
| <code>'''[DISTROBOX]'''</code> || Run this inside the Distrobox container after entering it
|}


== Prerequisites ==
== Prerequisites ==
Line 18: Line 31:
== Step 1: Install Distrobox on the Host ==
== Step 1: Install Distrobox on the Host ==


Install distrobox on your host system:
'''[HOST]''' Install Distrobox on your host system:


  sudo apt install distrobox    # Debian/Ubuntu
  sudo apt install distrobox    # Debian/Ubuntu
Line 26: Line 39:
== Step 2: Create a Distrobox Container ==
== Step 2: Create a Distrobox Container ==


Create a new container (Ubuntu-based in this example):
'''[HOST]''' Create a new container (Ubuntu-based in this example):


  distrobox create --name claude-container --image ubuntu:24.04
  distrobox create --name claude-container --image ubuntu:24.04


Enter the container:
'''[HOST]''' Enter the container:


  distrobox enter claude-container
  distrobox enter claude-container
Your prompt will change to indicate you are now inside the container.


== Step 3: Install Claude Code Inside the Container ==
== Step 3: Install Claude Code Inside the Container ==


Inside the distrobox container, install Node.js (if not already present) and Claude Code:
'''[DISTROBOX]''' Install Node.js (if not already present) and Claude Code:


  npm install -g @anthropic-ai/claude-code
  npm install -g @anthropic-ai/claude-code


Log in and verify it works:
'''[DISTROBOX]''' Log in and verify it works:


  claude
  claude
Line 46: Line 61:
== Step 4: Create a Dedicated Project Directory ==
== Step 4: Create a Dedicated Project Directory ==


Inside the container, create the directory where all Claude Code work will happen:
'''[DISTROBOX]''' Create the directory where all Claude Code work will happen:


  mkdir -p ~/claude_workspace
  mkdir -p ~/claude_workspace
Line 55: Line 70:
== Step 5: Install Firejail Inside the Container ==
== Step 5: Install Firejail Inside the Container ==


Inside the distrobox container:
'''[DISTROBOX]''' Install Firejail:


  sudo apt install firejail
  sudo apt install firejail


Verify the installation:
'''[DISTROBOX]''' Verify the installation:


  firejail --version
  firejail --version
Line 65: Line 80:
== Step 6: Create the Launcher Script ==
== Step 6: Create the Launcher Script ==


Inside the project directory (<code>~/claude_workspace</code>), create the launcher script <code>run_claude.sh</code>:
'''[DISTROBOX]''' Create the launcher script inside the project directory:


  nano ~/claude_workspace/run_claude.sh
  nano ~/claude_workspace/run_claude.sh
Line 74: Line 89:
#!/bin/bash
#!/bin/bash
# Launch Claude Code sandboxed to this directory using firejail
# Launch Claude Code sandboxed to this directory using firejail
# Usage: ./csb.sh [claude args...]
# Usage: ./run_claude.sh [claude args...]


WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
CLAUDE_DIR="$HOME/.claude"
CLAUDE_DIR="$HOME/.claude"
# Define NVM_DIR at the top so it's ready when needed
NVM_DIR="$HOME/.nvm"
NVM_DIR="$HOME/.nvm"


# Check firejail is installed
if ! command -v firejail &>/dev/null; then
if ! command -v firejail &>/dev/null; then
     echo "Error: firejail is not installed. Install with: sudo apt install firejail"
     echo "Error: firejail is not installed. Install with: sudo apt install firejail"
Line 87: Line 100:
fi
fi


# Check claude is installed
if ! command -v claude &>/dev/null; then
if ! command -v claude &>/dev/null; then
     echo "Error: claude is not installed or not in PATH"
     echo "Error: claude is not installed or not in PATH"
Line 110: Line 122:
</pre>
</pre>


Make it executable:
'''[DISTROBOX]''' Make it executable:


  chmod +x ~/claude_workspace/run_claude.sh
  chmod +x ~/claude_workspace/run_claude.sh
Line 116: Line 128:
== Step 7: Launch Claude Code in the Sandbox ==
== Step 7: Launch Claude Code in the Sandbox ==


Every time you want to use Claude Code, follow these steps:
'''[HOST]''' Enter your distrobox container:
 
'''1. Enter your distrobox container:'''


  distrobox enter claude-container
  distrobox enter claude-container


'''2. Navigate to the project directory:'''
'''[DISTROBOX]''' Navigate to the project directory:


  cd ~/claude_workspace
  cd ~/claude_workspace


'''3. Run the launcher script:'''
'''[DISTROBOX]''' Run the launcher script:


  ./run_claude.sh
  ./run_claude.sh


Claude Code will start, restricted to only the <code>~/claude_workspace</code> directory.
Claude Code will start, restricted to only the <code>~/claude_workspace</code> directory.
== Step 8: Save the Container as a Golden Image ==
Once the container is fully configured (Claude Code installed, Firejail set up, launcher script in place), save it as a reusable '''golden image'''. This means future sessions start from a clean, pre-configured state without reinstalling anything.
'''[HOST]''' First exit the container if you are still inside it:
exit
'''[HOST]''' Stop the container:
distrobox stop claude-container
'''[HOST]''' Commit the container state to a Podman image:
podman container commit claude-container localhost/claude-golden:latest
'''[HOST]''' Verify the image was created:
podman image ls | grep claude-golden
You now have a golden image stored locally. The original container can be kept or deleted — the image is self-contained.
=== Starting a Fresh Session from the Golden Image ===
Each new working session creates a throwaway container from the golden image. When the session ends, the container is deleted — leaving no trace.
'''[HOST]''' Create a new session container from the golden image:
distrobox create --name claude-session-1 --image localhost/claude-golden:latest
'''[HOST]''' Enter it:
distrobox enter claude-session-1
'''[DISTROBOX]''' Go to the workspace and start working:
cd ~/claude_workspace
./run_claude.sh
'''[HOST]''' When the session is done, delete the container entirely:
distrobox rm claude-session-1
=== Cloning the Golden Image for Multiple Parallel Sessions ===
You can run multiple independent sessions at the same time, each from the same golden image:
'''[HOST]'''
<pre>
distrobox create --name claude-session-A --image localhost/claude-golden:latest
distrobox create --name claude-session-B --image localhost/claude-golden:latest
distrobox create --name claude-session-C --image localhost/claude-golden:latest
</pre>
Each container is completely independent. Changes in session A do not affect session B or C.
=== Updating the Golden Image ===
When you want to update the base setup (e.g. upgrade Claude Code or install a new tool for all future sessions):
'''[HOST]''' Create a container from the current golden image:
distrobox create --name claude-update --image localhost/claude-golden:latest
'''[HOST]''' Enter it and make your changes:
distrobox enter claude-update
'''[DISTROBOX]''' Make updates (example):
npm update -g @anthropic-ai/claude-code
'''[HOST]''' Exit, stop, and commit a new golden image:
exit
distrobox stop claude-update
podman container commit claude-update localhost/claude-golden:latest
distrobox rm claude-update


== True Filesystem Isolation ==
== True Filesystem Isolation ==
Line 140: Line 229:


Firejail (Step 6) protects against this within a session, but for a fully isolated container that protects the host at the OS level, create the container with a '''separate home directory''' and <code>/run/host</code> mounted read-only:
Firejail (Step 6) protects against this within a session, but for a fully isolated container that protects the host at the OS level, create the container with a '''separate home directory''' and <code>/run/host</code> mounted read-only:
'''[HOST]''' Create a dedicated sandbox home directory:
mkdir -p ~/sandbox-homes/claude-isolated
'''[HOST]''' Create the isolated container:


<pre>
<pre>
# Create a dedicated sandbox home directory on the host
mkdir -p ~/sandbox-homes/claude-isolated
# Create the isolated container
distrobox create \
distrobox create \
   --name claude-isolated \
   --name claude-isolated \
Line 153: Line 244:
</pre>
</pre>


Enter it the same way:
'''[HOST]''' Enter it:


  distrobox enter claude-isolated
  distrobox enter claude-isolated
Line 160: Line 251:
* Claude Code can only write to <code>~/sandbox-homes/claude-isolated/</code> — your real home directory is untouched
* Claude Code can only write to <code>~/sandbox-homes/claude-isolated/</code> — your real home directory is untouched
* <code>/run/host</code> is read-only — host filesystem cannot be modified from inside the container
* <code>/run/host</code> is read-only — host filesystem cannot be modified from inside the container
* System package installs (<code>apt</code>, <code>pip</code>) remain container-only as before
* Deleting <code>~/sandbox-homes/claude-isolated/</code> after a session removes all traces
* If you delete <code>~/sandbox-homes/claude-isolated/</code> after a session, no trace remains on the host


=== What remains shared even with isolation ===
=== What remains shared even with isolation ===
Line 181: Line 271:
| X11/Wayland display || ❌ No || GUI apps render on host desktop
| X11/Wayland display || ❌ No || GUI apps render on host desktop
|}
|}
'''Note:''' The golden image and cloning workflow (Step 8) works identically with the isolated container — just use <code>--image localhost/claude-golden:latest</code> and <code>--home ~/sandbox-homes/claude-session-NAME</code> when creating each session container.


== What Each Layer Protects ==
== What Each Layer Protects ==
Line 203: Line 295:
# Run <code>sudo anything</code> — should be blocked
# Run <code>sudo anything</code> — should be blocked
# Read <code>~/.ssh/id_rsa</code> — should be inaccessible
# Read <code>~/.ssh/id_rsa</code> — should be inaccessible
== Summary of Commands ==
<pre>
# On the host — enter the container
distrobox enter claude-container
# Inside the container — go to the project directory
cd ~/claude_workspace
# Launch Claude Code in the sandbox
./run_claude.sh
</pre>


== Limitations ==
== Limitations ==
Line 231: Line 310:
* '''Better Integration than Docker:''' Unlike a raw Docker container, Distrobox allows the AI to easily access your home directory files (if mapped) and use your host's terminal tools, making the workflow smoother while still keeping the ''execution environment'' separate.
* '''Better Integration than Docker:''' Unlike a raw Docker container, Distrobox allows the AI to easily access your home directory files (if mapped) and use your host's terminal tools, making the workflow smoother while still keeping the ''execution environment'' separate.


=== 2. Can You Skip It? ===
=== Can You Skip Distrobox? ===


* '''Yes, if:''' You are just testing Claude Code, only plan to edit specific files, and will manually approve every command it tries to run (the default "safe" mode). Anthropic provides built-in sandboxing that is sufficient for basic use.
* '''Yes, if:''' You are just testing Claude Code, only plan to edit specific files, and will manually approve every command it tries to run (the default "safe" mode). Anthropic provides built-in sandboxing that is sufficient for basic use.
* '''No, if:''' You want to follow the "Burner" methodology—meaning you want to set the agent to '''autonomous mode''' (skipping permission prompts) or let it freely install tools. In this case, skipping the Distrobox layer is dangerous and defeats the purpose of the guide.
* '''No, if:''' You want to follow the "Burner" methodology — meaning you want to set the agent to '''autonomous mode''' (skipping permission prompts) or let it freely install tools. In this case, skipping the Distrobox layer is dangerous and defeats the purpose of the guide.
 
=== Summary ===
If you are following that specific wiki guide to build an '''autonomous''' or '''self-healing''' dev environment, '''do not skip the Distrobox step'''. It is the safety net that allows you to run the "burner" logic without nuking your daily driver.


== References ==
== References ==

Revision as of 13:32, 20 February 2026

Sandboxing Claude Code with Distrobox and Firejail

Overview

This guide documents how to run Claude Code in an isolated environment using two layers of sandboxing:

  1. Distrobox — runs Claude Code inside a Linux container, isolating it from the host system.
  2. Firejail — runs inside the container and further restricts Claude Code to a single project directory.

This protects against malicious prompt injection by limiting what Claude Code can access, even if it is tricked into running harmful commands.

Command Context

Every command in this guide is prefixed with where it must be run:

Prefix Meaning
[HOST] Run this in a terminal on your normal Linux desktop, outside any container
[DISTROBOX] Run this inside the Distrobox container after entering it

Prerequisites

  • A Linux host (Fedora, Ubuntu, Arch, etc.)
  • Distrobox installed on the host
  • A Claude Code account and API access

Step 1: Install Distrobox on the Host

[HOST] Install Distrobox on your host system:

sudo apt install distrobox    # Debian/Ubuntu
sudo dnf install distrobox    # Fedora
yay -S distrobox              # Arch (AUR)

Step 2: Create a Distrobox Container

[HOST] Create a new container (Ubuntu-based in this example):

distrobox create --name claude-container --image ubuntu:24.04

[HOST] Enter the container:

distrobox enter claude-container

Your prompt will change to indicate you are now inside the container.

Step 3: Install Claude Code Inside the Container

[DISTROBOX] Install Node.js (if not already present) and Claude Code:

npm install -g @anthropic-ai/claude-code

[DISTROBOX] Log in and verify it works:

claude

Step 4: Create a Dedicated Project Directory

[DISTROBOX] Create the directory where all Claude Code work will happen:

mkdir -p ~/claude_workspace
cd ~/claude_workspace

This is the only directory Claude Code will be able to access when sandboxed.

Step 5: Install Firejail Inside the Container

[DISTROBOX] Install Firejail:

sudo apt install firejail

[DISTROBOX] Verify the installation:

firejail --version

Step 6: Create the Launcher Script

[DISTROBOX] Create the launcher script inside the project directory:

nano ~/claude_workspace/run_claude.sh

With the following contents:

#!/bin/bash
# Launch Claude Code sandboxed to this directory using firejail
# Usage: ./run_claude.sh [claude args...]

WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
CLAUDE_DIR="$HOME/.claude"
NVM_DIR="$HOME/.nvm"

if ! command -v firejail &>/dev/null; then
    echo "Error: firejail is not installed. Install with: sudo apt install firejail"
    exit 1
fi

if ! command -v claude &>/dev/null; then
    echo "Error: claude is not installed or not in PATH"
    exit 1
fi

CLAUDE_BIN="$(which claude)"

echo "Starting Claude Code in sandbox..."
echo "  Allowed directory: $WORK_DIR"
echo "  Config directory:  $CLAUDE_DIR (read-write)"
echo "  NVM directory:     $NVM_DIR"
echo ""

exec firejail --noprofile \
    --whitelist="$WORK_DIR" \
    --whitelist="$CLAUDE_DIR" \
    --whitelist="$NVM_DIR" \
    --noroot \
    --caps.drop=all \
    "$CLAUDE_BIN" "$@"

[DISTROBOX] Make it executable:

chmod +x ~/claude_workspace/run_claude.sh

Step 7: Launch Claude Code in the Sandbox

[HOST] Enter your distrobox container:

distrobox enter claude-container

[DISTROBOX] Navigate to the project directory:

cd ~/claude_workspace

[DISTROBOX] Run the launcher script:

./run_claude.sh

Claude Code will start, restricted to only the ~/claude_workspace directory.

Step 8: Save the Container as a Golden Image

Once the container is fully configured (Claude Code installed, Firejail set up, launcher script in place), save it as a reusable golden image. This means future sessions start from a clean, pre-configured state without reinstalling anything.

[HOST] First exit the container if you are still inside it:

exit

[HOST] Stop the container:

distrobox stop claude-container

[HOST] Commit the container state to a Podman image:

podman container commit claude-container localhost/claude-golden:latest

[HOST] Verify the image was created:

podman image ls | grep claude-golden

You now have a golden image stored locally. The original container can be kept or deleted — the image is self-contained.

Starting a Fresh Session from the Golden Image

Each new working session creates a throwaway container from the golden image. When the session ends, the container is deleted — leaving no trace.

[HOST] Create a new session container from the golden image:

distrobox create --name claude-session-1 --image localhost/claude-golden:latest

[HOST] Enter it:

distrobox enter claude-session-1

[DISTROBOX] Go to the workspace and start working:

cd ~/claude_workspace
./run_claude.sh

[HOST] When the session is done, delete the container entirely:

distrobox rm claude-session-1

Cloning the Golden Image for Multiple Parallel Sessions

You can run multiple independent sessions at the same time, each from the same golden image:

[HOST]

distrobox create --name claude-session-A --image localhost/claude-golden:latest
distrobox create --name claude-session-B --image localhost/claude-golden:latest
distrobox create --name claude-session-C --image localhost/claude-golden:latest

Each container is completely independent. Changes in session A do not affect session B or C.

Updating the Golden Image

When you want to update the base setup (e.g. upgrade Claude Code or install a new tool for all future sessions):

[HOST] Create a container from the current golden image:

distrobox create --name claude-update --image localhost/claude-golden:latest

[HOST] Enter it and make your changes:

distrobox enter claude-update

[DISTROBOX] Make updates (example):

npm update -g @anthropic-ai/claude-code

[HOST] Exit, stop, and commit a new golden image:

exit
distrobox stop claude-update
podman container commit claude-update localhost/claude-golden:latest
distrobox rm claude-update

True Filesystem Isolation

The standard Distrobox setup above has two surfaces that reach the host filesystem even inside the container:

  1. Shared home directory — Distrobox mounts your real ~ inside the container. Anything written to ~/.config, ~/.local, ~/.bashrc, etc. affects the host immediately.
  2. /run/host mounted read-write — Distrobox mounts the entire host root filesystem at /run/host with write access, meaning code inside the container can modify host files outside the home directory.

Firejail (Step 6) protects against this within a session, but for a fully isolated container that protects the host at the OS level, create the container with a separate home directory and /run/host mounted read-only:

[HOST] Create a dedicated sandbox home directory:

mkdir -p ~/sandbox-homes/claude-isolated

[HOST] Create the isolated container:

distrobox create \
  --name claude-isolated \
  --image ubuntu:24.04 \
  --home ~/sandbox-homes/claude-isolated \
  --additional-flags "--mount type=bind,source=/,target=/run/host,ro"

[HOST] Enter it:

distrobox enter claude-isolated

With this setup:

  • Claude Code can only write to ~/sandbox-homes/claude-isolated/ — your real home directory is untouched
  • /run/host is read-only — host filesystem cannot be modified from inside the container
  • Deleting ~/sandbox-homes/claude-isolated/ after a session removes all traces

What remains shared even with isolation

Surface Isolated? Notes
Host home directory ✅ Yes Separate sandbox home used instead
Host filesystem via /run/host ✅ Yes Mounted read-only
System packages ✅ Yes Container overlay layer
Network ❌ No Container shares host network namespace; add --network=slirp4netns to --additional-flags to isolate
Linux kernel ❌ No Rootless container shares the host kernel (acceptable for most threat models)
X11/Wayland display ❌ No GUI apps render on host desktop

Note: The golden image and cloning workflow (Step 8) works identically with the isolated container — just use --image localhost/claude-golden:latest and --home ~/sandbox-homes/claude-session-NAME when creating each session container.

What Each Layer Protects

Layer What it does What it blocks
Distrobox Runs everything in a container Protects host system files, host packages, and host configuration from changes
Firejail Restricts filesystem access within the container Blocks access to everything outside ~/claude_workspace, prevents privilege escalation, drops Linux capabilities
run_claude.sh Automates launching with the correct flags Ensures you never accidentally run Claude Code without the sandbox

Verifying the Sandbox Works

Once Claude Code is running inside the sandbox, test it by asking Claude to:

  1. Read a file outside the project directory — should fail
  2. Run ls ~ — should only show whitelisted directories
  3. Run sudo anything — should be blocked
  4. Read ~/.ssh/id_rsa — should be inaccessible

Limitations

  • Firejail is Linux-only; this will not work on macOS or Windows.
  • Claude Code needs network access to reach the Anthropic API, so network is not blocked by default. Add --net=none to run_claude.sh to fully disable networking.
  • If ~/.claude is read-only, Claude Code cannot write session data (login tokens). Remove the --read-only line from the script if you wish to persist logins between sessions, though this slightly lowers security.
  • By default, Distrobox shares the home directory with the host. Use the isolated container setup in the True Filesystem Isolation section above to prevent this.

Why the Guide Uses Distrobox (The "Burner" Concept)

The "Burner Workflow" is designed to give the AI agent extensive permissions (e.g., auto-allow mode, running system commands, installing packages) without risking your actual computer. Distrobox is used to create a disposable container that feels like your native terminal but is actually isolated.

  • Safety with High Permissions: If you let Claude Code run rm -rf or install 50 different Node.js packages in a Distrobox, your main system remains untouched. If you do this on your host machine, you risk breaking your OS.
  • Dependency Hygiene: Claude Code agents often need to install tools (compilers, Python libraries, etc.) to complete tasks. Distrobox keeps this "junk" inside the box. When you are done, you can simply delete the box.
  • Better Integration than Docker: Unlike a raw Docker container, Distrobox allows the AI to easily access your home directory files (if mapped) and use your host's terminal tools, making the workflow smoother while still keeping the execution environment separate.

Can You Skip Distrobox?

  • Yes, if: You are just testing Claude Code, only plan to edit specific files, and will manually approve every command it tries to run (the default "safe" mode). Anthropic provides built-in sandboxing that is sufficient for basic use.
  • No, if: You want to follow the "Burner" methodology — meaning you want to set the agent to autonomous mode (skipping permission prompts) or let it freely install tools. In this case, skipping the Distrobox layer is dangerous and defeats the purpose of the guide.

References