# How Lemon AI's Docker VM Sandbox Isolates Code Execution for Security

> Discover how Lemon AI secures code execution using Docker VM sandbox isolation. Learn about process isolation, filesystem bind-mounts, and network controls preventing host access.

- Repository: [hexdocom/lemonai](https://github.com/hexdocom/lemonai)
- Tags: how-to-guide
- Published: 2026-03-03

---

**Lemon AI runs every user-generated action inside a dedicated Docker container called `lemon-runtime-sandbox`, using process isolation, filesystem bind-mounts, network bridge mode, and non-privileged execution to prevent host access.**

Lemon AI's Docker VM sandbox provides a secure, disposable environment for executing untrusted user code. By leveraging containerization, the platform ensures that each action runs in isolation from the host system and other users. This article examines the specific security mechanisms implemented in the `hexdocom/lemonai` repository, including process boundaries, filesystem restrictions, and network policies.

## Process Isolation

Each user request triggers the creation or reuse of a container named **`lemon-runtime-sandbox`**. Inside this container, a dedicated Node.js process runs [`action_execution_server.js`](https://github.com/hexdocom/lemonai/blob/main/action_execution_server.js) to handle code execution. No host-level processes are exposed to the container, and the container lifecycle is managed independently of the main application.

In [`src/runtime/DockerRuntime.local.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.local.js), the `connect_container` method handles this logic:

```javascript
// src/runtime/DockerRuntime.local.js
async connect_container() {
  try {
    // Try to reuse an existing sandbox container
    const container = docker.getContainer('lemon-runtime-sandbox')
    const info = await container.inspect()
    if (info.State.Status === 'exited') await container.start()
  } catch (err) {
    // Container not found → create a fresh one
    const container = await this.init_container()
  }
  // Record the dynamically assigned ports
  const info = await container.inspect()
  this.host_port  = Object.keys(info.NetworkSettings.Ports)[0].split('/')[0]
  this.vscode_port = Object.keys(info.NetworkSettings.Ports)[1].split('/')[0]
  // …
}

```

## Filesystem Isolation

The sandbox restricts filesystem access through **bind-mounting**. Only the user's workspace directory is mounted into the container at `/workspace` with read-write permissions. The rest of the container filesystem is built fresh from the runtime image, preventing access to host system files.

This is configured in `init_container` within [`src/runtime/DockerRuntime.local.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.local.js):

```javascript
// src/runtime/DockerRuntime.local.js – init_container (Binds)
HostConfig: {
  Binds: [`${this.workspace_dir}:/workspace:rw`],
  // …
}

```

## Network Isolation

Network traffic is isolated using Docker's default **bridge network**. The container does not use `host` network mode. Instead, Docker assigns random host ports from safe ranges that are forwarded to the container's internal ports, preventing direct network access to the host or other containers.

The port binding configuration in `init_container` shows this setup:

```javascript
// src/runtime/DockerRuntime.local.js – init_container (PortBindings)
HostConfig: {
  PortBindings: {
    '3000/tcp': [{ HostPort: '0' }],  // Random host port
    '8080/tcp': [{ HostPort: '0' }]   // Random host port
  },
  // …
}

```

## Resource Limits and Privilege Restrictions

The sandbox runs **without privileged mode** and without additional Linux capabilities. The container inherits default Docker cgroup limits for CPU and memory unless explicitly overridden. This prevents container escape vulnerabilities and resource exhaustion attacks.

The `init_container` method explicitly omits the `Privileged` flag, relying on Docker's default security profile.

## Image Trust and Verification

The sandbox image **`hexdolemonai/lemon-runtime-sandbox:latest`** is built from a controlled Dockerfile that installs only required runtimes and tools. Before the UI launches, Lemon AI verifies that Docker is installed and that the required image is present. If missing, the platform pulls it automatically.

In [`dockerSetupService.js`](https://github.com/hexdocom/lemonai/blob/main/dockerSetupService.js), the `REQUIRED_DOCKER_IMAGE` constant and `checkDockerEnvironmentReady` function handle this:

```javascript
// dockerSetupService.js
const REQUIRED_DOCKER_IMAGE = 'hexdolemonai/lemon-runtime-sandbox:latest';

async function checkDockerEnvironmentReady() {
  return new Promise((resolve) => {
    exec(`docker images -q ${REQUIRED_DOCKER_IMAGE}`, (err, stdout) => {
      resolve(stdout.trim().length > 0);
    });
  });
}

```

## Remote Deployment Isolation

For remote deployments, Lemon AI uses the same sandbox image on an external ECI (Elastic Container Instance) server. The [`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js) file handles remote initialization, ensuring that even when execution occurs on a remote host, the same isolation boundaries apply.

```javascript
// src/runtime/DockerRuntime.js – init_container (ECI request)
async init_container() {
  // Request remote ECI to create container with same image and constraints
  const response = await requestECI({
    image: 'hexdolemonai/lemon-runtime-sandbox:latest',
    binds: [`${this.workspace_dir}:/workspace:rw`],
    // ... same security constraints
  });
}

```

## Summary

Lemon AI's Docker VM sandbox implements defense in depth through multiple isolation layers:

- **Process isolation** via dedicated `lemon-runtime-sandbox` containers running [`action_execution_server.js`](https://github.com/hexdocom/lemonai/blob/main/action_execution_server.js) independently of host processes
- **Filesystem isolation** through selective bind-mounting of only the workspace directory (`/workspace`)
- **Network isolation** using Docker bridge mode with randomly assigned host ports, avoiding `host` network exposure
- **Privilege restrictions** by running without `--privileged` mode or additional capabilities
- **Image verification** ensuring only the trusted `hexdolemonai/lemon-runtime-sandbox` image executes user code

## Frequently Asked Questions

### How does Lemon AI prevent containers from accessing host files?

Lemon AI restricts filesystem access by bind-mounting only the specific workspace directory (`${this.workspace_dir}:/workspace:rw`) when initializing the container in [`src/runtime/DockerRuntime.local.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.local.js). The rest of the container filesystem is built fresh from the runtime image, preventing access to sensitive host paths like `/etc`, `/root`, or system binaries.

### Can user code escape the Docker sandbox and run on the host?

Container escape is mitigated by running the sandbox without privileged mode (`Privileged: false`) and without additional Linux capabilities. The container uses the default Docker security profile and inherits cgroup limits for resource constraints. Additionally, the `lemon-runtime-sandbox` container runs as an isolated Node.js process ([`action_execution_server.js`](https://github.com/hexdocom/lemonai/blob/main/action_execution_server.js)) with no direct access to host namespaces or devices.

### What happens if the required Docker image is missing when starting Lemon AI?

Before launching the UI, [`dockerSetupService.js`](https://github.com/hexdocom/lemonai/blob/main/dockerSetupService.js) runs `checkDockerEnvironmentReady()` to verify that the `hexdolemonai/lemon-runtime-sandbox:latest` image exists locally. If the image is missing, the service automatically pulls it from the registry or loads it from a verified tarball. The application only proceeds once the image is confirmed present, ensuring consistent sandbox environments.

### Does Lemon AI support remote sandbox execution?

Yes, Lemon AI supports remote execution through the [`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js) module. When configured for remote ECI (Elastic Container Instance) deployment, the platform launches the same `lemon-runtime-sandbox` image on the remote host using identical isolation constraints: filesystem bind-mounts, bridge networking, and non-privileged execution. This ensures security parity between local and remote execution environments.