Introduction to Fence
Relevant source files
The following files were used as context for generating this wiki page:
Fence is a cross-platform sandboxing tool designed to wrap arbitrary commands in a restricted environment. Its primary purpose is to block network access by default, restrict filesystem operations based on configurable rules, and prevent the execution of dangerous system commands. It is specifically built to run semi-trusted code, such as package installations, build scripts, or unfamiliar repositories, and serves as a defense-in-depth layer for AI coding agents like Claude Code or Cursor Agent.
Sources: README.md:9-16, ARCHITECTURE.md:3-8
Core Architecture and Components
Fence operates by intercepting system-level operations through a combination of proxying and platform-specific sandboxing mechanisms. The orchestration is handled by a Manager which manages the lifecycle of the sandbox, including proxy initialization and environment sanitization.
The following diagram illustrates the high-level relationship between configuration, the internal manager, and the enforcement mechanisms:
Key Components
| Component | Description | Relevant Files |
|---|---|---|
| CLI Entry Point | Handles argument parsing, template loading, and user interaction via Cobra. | cmd/fence/main.go |
| Sandbox Manager | Orchestrates proxy servers, platform-specific bridges, and cleanup on exit. | internal/sandbox/manager.go |
| Filtering Proxies | HTTP and SOCKS5 proxies that filter outbound traffic based on domain allowlists. | internal/proxy/ |
| Command Blocker | Parses and blocks dangerous shell commands before execution. | internal/sandbox/command.go |
| Public API | Provides a Go package for programmatic library usage. | pkg/fence/fence.go |
Sources: ARCHITECTURE.md:28-56, README.md:73-75
Sandbox Lifecycle and Execution Flow
The execution of a sandboxed command follows a strict sequence: initializing proxies, validating the command against deny lists, wrapping the command in OS-specific isolation, and sanitizing the environment.
Platform Implementations
Fence utilizes native OS features to enforce isolation:
- macOS: Uses
sandbox-execwith Seatbelt profiles to filter syscalls and filesystem access. - Linux: Employs
bubblewrap(bwrap) for namespace isolation,Landlockfor filesystem control, andseccompfor syscall filtering.
Sources: ARCHITECTURE.md:93-132, ARCHITECTURE.md:188-202
Configuration and Security Policies
Fence uses a JSON-based configuration model, supporting inheritance via an extends field. It defaults to a restrictive "deny-all" network policy.
Data Structures
The Config struct is the central data model for defining sandbox boundaries:
type Config struct {
Extends string `json:"extends,omitempty"`
Network NetworkConfig `json:"network"`
Filesystem FilesystemConfig `json:"filesystem"`
Command CommandConfig `json:"command"`
SSH SSHConfig `json:"ssh"`
AllowPty bool `json:"allowPty,omitempty"`
}
Sources: internal/config/config.go:18-25
Default Restrictions
Fence includes a DefaultDeniedCommands list to block high-risk operations:
- System Control:
shutdown,reboot,halt. - Kernel Manipulation:
modprobe,insmod. - Disk Operations:
mkfs,fdisk,dd if=. - Escape Vectors:
chroot,unshare,docker run --privileged.
Sources: internal/config/config.go:61-105
Network Isolation and Proxying
To block network access while allowing specific domains, Fence sets up local proxies. On Linux, because bwrap --unshare-net completely isolates the network namespace, Fence uses socat bridges and Unix sockets to tunnel traffic from the sandbox to the host proxies.
Network Configuration Fields
| Field | Type | Description |
|---|---|---|
allowedDomains | []string | Whitelist of domains (supports *.domain.com). |
allowLocalOutbound | *bool | Controls if the app can connect to localhost services (e.g., Redis). |
allowLocalBinding | bool | Allows servers inside the sandbox to listen on ports. |
Sources: internal/config/config.go:28-37, ARCHITECTURE.md:73-81
External Integrations: Claude Code
Fence provides specialized support for importing security policies from Claude Code. It maps Claude's permission model (Bash, Read, Write, Edit) into Fence's command and filesystem configurations.
// ConvertClaudeToFence maps Claude permissions to Fence internal structures
func ConvertClaudeToFence(settings *ClaudeSettings) *config.Config {
cfg := config.Default()
// ... processes settings.Permissions.Allow, Deny, and Ask
return cfg
}
Sources: internal/importer/claude.go:68-88, cmd/fence/main.go:253-290
Summary
Fence provides a lightweight, container-free sandbox for developers and AI agents. By combining domain-filtering proxies with OS-native process isolation (Seatbelt on macOS and Bubblewrap/Landlock on Linux), it allows for granular control over network, filesystem, and command execution without the overhead of full virtualization or heavy container runtimes.
Sources: README.md:1-8, ARCHITECTURE.md:204-210