MCP Server Sandboxing

Plugged.in implements robust sandboxing for all STDIO MCP servers to ensure security and resource isolation. This guide covers the sandboxing architecture, configuration, and best practices.

Overview

Sandboxing is enabled by default for all STDIO MCP servers. Never disable sandboxing in production environments unless absolutely necessary.
Sandboxing provides:
  • Process Isolation: Each MCP server runs in its own isolated environment
  • Filesystem Protection: Restricted access to system files and directories
  • Resource Limits: CPU, memory, and I/O constraints
  • Network Control: Optional network isolation for untrusted servers
  • Privilege Dropping: Servers run with minimal privileges

Sandboxing Technologies

Bubblewrap (Primary)

Bubblewrap is the preferred sandboxing technology due to its lightweight nature and user-namespace support.
Features:
  • User namespace isolation (no root required)
  • Bind mount control for selective file access
  • Network namespace support
  • Resource limits via cgroups
  • Minimal performance overhead
Installation:
# Ubuntu/Debian
sudo apt-get install -y bubblewrap

# RHEL/CentOS/Fedora
sudo dnf install -y bubblewrap

# Verify installation
bwrap --version

Firejail (Fallback)

Firejail provides SUID-based sandboxing with extensive security profiles. Features:
  • Extensive security profiles
  • AppArmor/SELinux integration
  • X11 sandboxing support
  • Network filtering capabilities
  • Comprehensive logging
Installation:
# Ubuntu/Debian
sudo apt-get install -y firejail

# RHEL/CentOS/Fedora
sudo dnf install -y firejail

# Verify installation
firejail --version

FUSE Requirements

Some applications require FUSE (Filesystem in Userspace) support:
# Install FUSE3
sudo apt-get install -y fuse3 libfuse3-3

# Enable FUSE for containers
sudo modprobe fuse

# Verify FUSE is available
fusermount3 --version

Configuration

Environment Variables

Configure sandboxing behavior through environment variables:
# Sandboxing Type
MCP_ISOLATION_TYPE=bubblewrap      # Options: bubblewrap | firejail | none
MCP_ISOLATION_FALLBACK=firejail    # Fallback if primary not available

# Network Isolation
MCP_ENABLE_NETWORK_ISOLATION=false # Set to true for strict isolation

# Resource Limits
MCP_CPU_CORES_MAX=0.5              # Maximum CPU cores (0.5 = 50% of one core)
MCP_MEMORY_MAX_MB=512              # Maximum memory in MB
MCP_IO_READ_MBPS=10                # I/O read limit in MB/s
MCP_IO_WRITE_MBPS=5                # I/O write limit in MB/s
MCP_PROCESS_TIMEOUT_MS=300000      # Process timeout in milliseconds
MCP_STARTUP_TIMEOUT_MS=10000       # Startup timeout in milliseconds

# Package Storage
MCP_PACKAGE_STORE_DIR=/var/mcp-packages
MCP_PNPM_STORE_DIR=/var/mcp-packages/pnpm-store
MCP_UV_CACHE_DIR=/var/mcp-packages/uv-cache

Sandboxing Modes

Default and recommended mode
// Bubblewrap configuration
{
  isolation: {
    type: "bubblewrap",
    config: {
      unshareAll: true,          // Unshare all namespaces
      shareNet: true,             // Allow network (configurable)
      dieWithParent: true,        // Terminate on parent exit
      newSession: true,           // New session for process
      uid: 1000,                  // Run as non-root user
      gid: 1000,                  // Run as non-root group
      hostname: "mcp-sandbox",    // Isolated hostname
      capDrop: ["ALL"],          // Drop all capabilities
      capAdd: ["CAP_NET_BIND_SERVICE"] // Add specific capabilities
    }
  }
}

Implementation Details

Filesystem Isolation

The sandboxing system creates isolated filesystem views:
// Bubblewrap filesystem bindings
const filesystemBindings = [
  // Read-only system directories
  { source: "/usr", target: "/usr", readonly: true },
  { source: "/lib", target: "/lib", readonly: true },
  { source: "/lib64", target: "/lib64", readonly: true },

  // Writable workspace
  { source: "/tmp/mcp-workspace", target: "/workspace", readonly: false },

  // Package manager directories
  { source: MCP_PACKAGE_STORE_DIR, target: MCP_PACKAGE_STORE_DIR, readonly: false },

  // Optional: User home (restricted)
  { source: "~/.config", target: "~/.config", readonly: true }
];

Resource Limits

Resource constraints applied to sandboxed processes:
// Resource limit configuration
const resourceLimits = {
  cpu: {
    cores: 0.5,                    // 50% of one CPU core
    nice: 10                       // Lower priority
  },
  memory: {
    max: 512 * 1024 * 1024,       // 512 MB
    swap: 0                        // No swap usage
  },
  io: {
    readBandwidth: 10 * 1024 * 1024,  // 10 MB/s read
    writeBandwidth: 5 * 1024 * 1024,  // 5 MB/s write
    maxOpenFiles: 1024             // File descriptor limit
  },
  process: {
    maxProcesses: 32,              // Process limit
    timeout: 300000                // 5 minute timeout
  }
};

Network Isolation

Control network access for sandboxed servers:

Security Considerations

Privilege Escalation Prevention

  1. Drop All Capabilities: Remove all Linux capabilities by default
  2. No New Privileges: Prevent privilege escalation via setuid
  3. User Namespace: Run in unprivileged user namespace
  4. Seccomp Filtering: Restrict system calls

Directory Traversal Protection

// Path validation for sandbox
function validateSandboxPath(path: string): boolean {
  const normalized = path.normalize(path);
  const resolved = path.resolve(path);

  // Prevent directory traversal
  if (normalized.includes('..')) return false;

  // Ensure path is within allowed directories
  const allowedPaths = [
    '/tmp/mcp-workspace',
    MCP_PACKAGE_STORE_DIR
  ];

  return allowedPaths.some(allowed =>
    resolved.startsWith(allowed)
  );
}

OAuth and Authentication

Special handling for OAuth-enabled MCP servers:
// OAuth directory isolation
if (server.requiresOAuth) {
  const oauthDir = path.join(
    MCP_PACKAGE_STORE_DIR,
    'servers',
    server.uuid,
    'oauth'
  );

  // Bind OAuth directory for token storage
  filesystemBindings.push({
    source: oauthDir,
    target: oauthDir,
    readonly: false
  });
}

Troubleshooting

Common Issues

Debug Mode

Enable debug logging for sandboxing:
# Enable sandbox debugging
export DEBUG=mcp:sandbox
export MCP_SANDBOX_VERBOSE=true

# View sandbox configuration
cat /proc/[PID]/status | grep Cap
cat /proc/[PID]/cgroup

Testing Sandboxing

Verify sandboxing is working:
# Test with bubblewrap
bwrap \
  --unshare-all \
  --share-net \
  --die-with-parent \
  --ro-bind /usr /usr \
  --ro-bind /lib /lib \
  --ro-bind /lib64 /lib64 \
  --tmpfs /tmp \
  --proc /proc \
  --dev /dev \
  -- /bin/sh -c "echo 'Sandbox works!'"

# Test with firejail
firejail \
  --quiet \
  --private=/tmp/test \
  --noroot \
  --net=none \
  -- /bin/sh -c "echo 'Firejail works!'"

Best Practices

1

Always Use Sandboxing

Never disable sandboxing in production. If a server requires it, investigate alternatives.
2

Principle of Least Privilege

Grant minimal permissions required for functionality.
3

Regular Updates

Keep sandboxing tools updated for latest security fixes.
4

Monitor Resource Usage

Track CPU, memory, and I/O usage to tune limits.
5

Test Thoroughly

Test MCP servers in sandbox before production deployment.
6

Document Exceptions

If sandboxing must be disabled, document the reason and compensating controls.

Performance Impact

Sandboxing overhead is minimal:
MetricNo SandboxBubblewrapFirejail
Startup Time100ms120ms (+20%)150ms (+50%)
Memory Overhead0 MB2-4 MB5-10 MB
CPU Overhead0%< 1%1-2%
I/O Overhead0%< 1%2-3%

Platform-Specific Notes

Docker Containers

For Docker deployments:
# Install sandboxing tools in container
RUN apt-get update && apt-get install -y \
    bubblewrap \
    firejail \
    fuse3

# Enable required capabilities
docker run \
  --cap-add SYS_ADMIN \
  --cap-add NET_ADMIN \
  --security-opt apparmor=unconfined \
  --device /dev/fuse \
  pluggedin:latest

Kubernetes

For Kubernetes deployments:
securityContext:
  capabilities:
    add:
      - SYS_ADMIN
      - NET_ADMIN
  privileged: false
  runAsNonRoot: true
  runAsUser: 1000

Support

For sandboxing assistance: