https://github.com/dspearson/claude-confined
claude-confined: take back control.
https://github.com/dspearson/claude-confined
Last synced: 8 months ago
JSON representation
claude-confined: take back control.
- Host: GitHub
- URL: https://github.com/dspearson/claude-confined
- Owner: dspearson
- License: isc
- Created: 2025-10-07T21:52:43.000Z (9 months ago)
- Default Branch: master
- Last Pushed: 2025-10-07T23:11:23.000Z (9 months ago)
- Last Synced: 2025-10-08T00:10:18.988Z (9 months ago)
- Language: Perl
- Homepage:
- Size: 268 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Claude Confined

Take back control.
## Overview
Run Claude Code in a sandboxed environment using bubblewrap, AppArmor, and seccomp filters to restrict filesystem access, prevent credential leakage, and limit system capabilities.
**Security layers:**
- **Bubblewrap** - User namespace containerization and filesystem isolation
- **AppArmor** - Mandatory Access Control (MAC) with explicit deny rules for sensitive files
- **Seccomp** - Berkeley Packet Filter (BPF) syscall filtering
## Requirements
### Required
- **bubblewrap** (bwrap) - Containerization and namespace isolation
- Debian/Ubuntu: `sudo apt-get install bubblewrap`
- Fedora/RHEL: `sudo dnf install bubblewrap`
- Arch: `sudo pacman -S bubblewrap`
- **AppArmor** - Mandatory Access Control
- Usually pre-installed on Ubuntu/Debian
- Check status: `sudo aa-status`
- Install: `sudo apt-get install apparmor apparmor-utils`
- **gcc** and **libseccomp-dev** - For compiling seccomp filters
- Debian/Ubuntu: `sudo apt-get install gcc libseccomp-dev`
- Fedora/RHEL: `sudo dnf install gcc libseccomp-devel`
- Arch: `sudo pacman -S gcc libseccomp`
### Auto-installed if missing
The installer will automatically install these if they're not found:
- **bun** - JavaScript runtime (installed via official installer)
- **Claude Code** - Installed via `bun install -g @anthropic-ai/claude-code`
## Installation
```bash
# Basic installation (installs to ~/.local/bin)
bin/install
# Installation with permanently allowed directories
# (adds directories to AppArmor profile for persistent access)
bin/install --allow /home/user/projects --allow /workspace
# View all installation options
bin/install --help
```
**Important notes:**
- Do NOT run with `sudo` - the installer uses sudo internally when needed
- Installation requires sudo access for AppArmor profile deployment
- The installer is interactive and checks all requirements
- Bun and Claude Code will be installed automatically if missing
**Post-installation:**
Ensure `~/.local/bin` is in your PATH:
```bash
export PATH="${HOME}/.local/bin:${PATH}"
```
Add this to your `~/.bashrc` or `~/.zshrc` to make it permanent.
## Usage
### Basic Usage
```bash
# Run Claude Code in sandboxed environment
claude-confined
# Pass arguments to Claude normally
claude-confined chat
# The current working directory is automatically accessible
cd ~/my-project
claude-confined
```
### Runtime Directory Access
Add additional directories at runtime (temporary, not saved to AppArmor profile):
```bash
# Allow read-write access to additional paths
claude-confined --allow /path/to/project
# Allow read-only access
claude-confined --ro-allow /path/to/docs
# Multiple paths
claude-confined --allow /home/user/project1 --ro-allow /usr/share/docs
# Combine with Claude arguments
claude-confined --allow /path/to/project chat
```
**Installation vs Runtime `--allow` flags:**
- **Installation time** (`bin/install --allow PATH`): Permanently adds directory to AppArmor profile
- **Runtime** (`claude-confined --allow PATH`): Temporarily grants access for that execution only
### Debug Mode
Inspect the sandbox environment:
```bash
# Run arbitrary command inside sandbox
claude-confined --bash "ls -la ~"
claude-confined --bash "env"
claude-confined --bash "cat /proc/self/status"
```
### Environment Variables
```bash
# Skip permission checks (use with caution)
DANGEROUSLY_SKIP_PERMISSIONS=1 claude-confined
```
## Emacs Integration
Use `claude-confined` directly in Emacs with [`claude-code.el`](https://github.com/stevemolitor/claude-code.el):
**For Doom Emacs:**
```bash
# Add doom-packages.el to ~/.config/doom/packages.el
# Add doom-config.el to ~/.config/doom/config.el
doom sync
```
**For Vanilla Emacs:**
```elisp
;; Add to your Emacs init file
(load-file "/path/to/claude-confined/claude-code-emacs.el")
```
Features:
- **vterm backend** for fast terminal emulation
- **monet integration** for LSP functionality
- **Sandboxed execution** with all claude-confined security features
- Helper functions to grant additional directory access
See [emacs/EMACS.md](emacs/EMACS.md) for complete installation and usage instructions.
## Security Model
### Filesystem Access
**Allowed by default:**
- **Current working directory** - Full read/write access
- **`~/.claude/`** - Full read/write (Claude state, temporary files, logs)
- **`~/.config/claude/`** - Read/write (Claude configuration)
- **`~/.claude/ssh/`** - Mapped to `~/.ssh` inside sandbox (if directory exists)
- **System binaries** - Read/execute only (`/usr`, `/bin`, `/lib`, etc.)
- **Nix store** - Read/execute only (if `/nix` exists)
- **Additional paths** - Via `--allow` or `--ro-allow` flags
**Explicitly denied:**
- **`~/.ssh/`** - SSH keys (host directory, use `~/.claude/ssh/` instead)
- **`~/.gnupg/`** - GPG keys
- **`~/.aws/`, `~/.docker/`, `~/.kube/`** - Cloud credentials
- **`~/.bash_history`, `~/.zsh_history`** - Shell history files
- **`~/.netrc`, `~/.pypirc`, `~/.npmrc`** - Package manager credentials
- **`~/.cargo/credentials`** - Rust package credentials
- **`/etc/shadow`, `/etc/sudoers`** - System sensitive files
- **`/root/`** - Root user directory
### Process Capabilities
- **Cannot execute** `sudo`, `su`, `mount`, `umount`
- **Cannot access** other users' files
- **Runs in isolated namespaces** (UTS, IPC, user)
- **No dangerous capabilities** inside namespace
### Network Access
- Network is **enabled** to allow Claude to communicate with Anthropic's API
- Uses host network namespace (no network isolation)
### Syscall Filtering
Seccomp BPF filters block dangerous system calls.
## Testing
Run security tests to verify the sandbox:
```bash
# Using just (if installed)
just test
# Or run tests directly (requires claude-confined to be installed)
cd ~/.claude/tmp && cp bin/run-tests . && claude-confined --bash "perl run-tests"
```
Tests verify:
- Sensitive files are blocked (`.gnupg/`, `.aws/`, `/etc/shadow`, etc.)
- Allowed directories are accessible (`.claude/`, current directory)
- Dangerous commands are blocked (`sudo`, `su`)
## Monitoring and Auditing
AppArmor logs all denied operations. Monitor logs to detect issues:
```bash
# View recent AppArmor denials
sudo ausearch -m AVC -ts recent | grep claude-confined
# Or check system journal
sudo journalctl -xe | grep -i apparmor | grep claude-confined
# Or check kernel logs
sudo dmesg | tail -100 | grep -i apparmor
```
## Customisation
### Modifying AppArmor Profile
Edit the profile template and reinstall:
```bash
# Edit the profile
vim apparmor/claude-confined
# Reinstall to apply changes
bin/install
```
The profile uses three layers:
1. **claude-confined** - Outer wrapper profile
2. **claude-confined-bwrap** - Bubblewrap execution profile (with capabilities)
3. **claude-confined-unpriv** - Unprivileged profile for processes inside namespace
### Adding Permanent Directory Access
Add directories to the AppArmor profile permanently:
```bash
bin/install --allow /home/user/projects --allow /workspace
```
This modifies the installed AppArmor profile to grant access to these directories.
### Optional Profiles for Configuration Directories
By default, Claude is restricted from accessing configuration directories like `~/.config/emacs` or `~/.config/doom` to prevent sandbox escapes when integrated with editors. However, you can temporarily enable optional profiles when you specifically want Claude to help with configurations:
```bash
# List available optional profiles
just list-profiles
# Check which profiles are enabled
just profile-status
# Enable a profile (e.g., to let Claude edit your Emacs config)
just enable-profile emacs-config
# Work with Claude on your configuration
claude-confined
# Disable when done
just disable-profile emacs-config
```
**Available optional profiles:**
- **`emacs-config`** - Grants access to Emacs and Doom configuration directories
- **`browser-config`** - Grants access to Firefox/Chrome configuration
- **`full-config-access`** - Grants access to all `~/.config` (use sparingly)
**Best practices:**
- Only enable profiles when you need them
- Disable profiles immediately after completing your task
- Use specific profiles (`emacs-config`) rather than broad ones (`full-config-access`)
- Check `just profile-status` regularly to see what's enabled
See [apparmor/optional/README.md](apparmor/optional/README.md) for details on creating custom optional profiles.
## Uninstallation
```bash
# Uninstall claude-confined
bin/install --uninstall
```
This removes:
- Wrapper script (`~/.local/bin/claude-confined`)
- Seccomp generator (`~/.local/lib/claude-confined/`)
- AppArmor profile (`/etc/apparmor.d/claude-confined`)
- Bun (only if installed by claude-confined installer)
**Not removed:**
- `~/.claude/` directory (your Claude data and SSH keys)
- Claude Code (if installed separately or used by other tools)
## Troubleshooting
### Installation fails with "sudo access required"
The installer needs sudo to install the AppArmor profile. Ensure you have sudo privileges and try again.
### "Error: claude not found in PATH"
Ensure the installer completed successfully and `~/.local/bin` is in your PATH:
```bash
export PATH="${HOME}/.local/bin:${PATH}"
```
### "Operation not permitted" errors
- Check AppArmor status: `sudo aa-status | grep claude-confined`
- Review AppArmor logs: `sudo journalctl -xe | grep -i apparmor`
- Ensure bubblewrap is installed: `which bwrap`
### AppArmor profile not loading
```bash
# Check for syntax errors
sudo apparmor_parser -r /etc/apparmor.d/claude-confined
# View AppArmor logs
sudo dmesg | grep -i apparmor
```
### Claude can't access files
- Ensure you're running from the correct directory (CWD is automatically accessible)
- Use `--allow /path/to/dir` to add additional directories at runtime
- Check file permissions: `ls -la`
- For permanent access, reinstall with `bin/install --allow /path/to/dir`
## How It Works
1. **Wrapper script** (`bin/claude-confined`) sets up the bubblewrap sandbox
2. **Bubblewrap** creates isolated namespaces and bind-mounts filesystem
3. **AppArmor** enforces MAC policy on all processes (three-layer profile)
4. **Seccomp** filters dangerous syscalls (when enabled)
5. **Claude Code** runs inside the sandbox with restricted access
The current directory is bind-mounted into the sandbox, allowing Claude to work on your project files while blocking access to sensitive home directory files.
## Development
### Using direnv
This project includes a `.envrc` file for [direnv](https://direnv.net/) that automatically displays available commands when you enter the directory:
```bash
# Install direnv (if not already installed)
sudo apt-get install direnv
# Add to your shell (~/.bashrc or ~/.zshrc):
eval "$(direnv hook bash)" # for bash
eval "$(direnv hook zsh)" # for zsh
# Allow the .envrc in this directory:
direnv allow
```
Now whenever you `cd` into the claude-confined directory, you'll see the available `just` commands automatically.
## Licence
ISC Licence - see [LICENCE](LICENCE) file for details.