How AstrBot's Agent Sandbox Isolates Code Execution for Security

AstrBot isolates agent code execution by running it inside sandboxed containers managed through pluggable booters like Shipyard Neo or Boxlite, enforcing process isolation, filesystem isolation, capability gating, and automatic TTL expiration.

AstrBot is an open-source LLM agent framework that enables AI agents to execute code, interact with shells, and manipulate files. To prevent malicious or buggy agent code from compromising the host system, AstrBot implements a robust Agent Sandbox architecture that delegates all execution to isolated runtime environments. This article examines how the sandbox system works, from configuration to lifecycle management, based on the implementation in the AstrBotDevs/AstrBot repository.

Configuration and Sandbox Selection

The sandbox system is controlled through the provider_settings configuration in astrbot/core/config/default.py. By default, the computer_use_runtime is set to "none", but enabling agent capabilities requires setting it to "sandbox" and configuring a booter implementation.

{
  "computer_use_runtime": "sandbox",
  "sandbox": {
    "booter": "shipyard_neo",
    "shipyard_neo_endpoint": "",
    "shipyard_neo_access_token": "",
    "shipyard_neo_profile": "python-default",
    "shipyard_neo_ttl": 3600
  }
}

The booter field determines which isolation backend to use. Shipyard Neo connects to an external Bay service or spins up local Docker containers, while Boxlite provides a lightweight mock container for local testing. This pluggable architecture allows operators to choose between full container isolation or lightweight sandboxing based on deployment constraints.

Shipyard Neo Booter: Container-Based Isolation

The ShipyardNeoBooter class in astrbot/core/computer/booters/shipyard_neo.py implements the core isolation logic by managing Docker-based Bay containers. It creates fresh sandbox instances for each session, ensuring complete separation between agent executions.

Auto-Start Mode and Docker Containers

When the shipyard_neo_endpoint is set to "__auto__" or left empty, the booter automatically launches a local Docker container using BayContainerManager. This spawns an isolated process space separate from the AstrBot host process.


# From shipyard_neo.py lines 10-27

if endpoint in ("__auto__", ""):
    self.container_manager = BayContainerManager()
    await self.container_manager.start()
    credentials = self.container_manager.get_credentials()
    endpoint = credentials["endpoint"]
    access_token = credentials["access_token"]

The container runs its own Python interpreter and shell, with filesystem mounts strictly limited to the container's own directories.

Sandbox Creation and TTL

After authentication, the booter creates a fresh sandbox with a defined time-to-live (TTL). The default TTL of 3600 seconds ensures that even if cleanup fails, the sandbox will automatically expire, limiting the window for any malicious activity.


# From shipyard_neo.py lines 48-55

self._sandbox = await self._client.create_sandbox(
    profile=self.config.get("shipyard_neo_profile", "python-default"),
    ttl=self.config.get("shipyard_neo_ttl", 3600)
)

Capability Restriction

The sandbox advertises only specific capabilities through self._sandbox.capabilities. The booter selectively exposes tools based on these capabilities, preventing agents from accessing functionality not explicitly granted (such as browsers, network access, or GPUs).


# From shipyard_neo.py lines 90-100

if "browser" in self._sandbox.capabilities:
    self._browser = NeoBrowserComponent(self._sandbox)
else:
    self._browser = None

Isolated Execution Components

The ShipyardNeoBooter exposes four isolated execution components, each wrapping sandbox-specific functionality while keeping the host process insulated:

Component Implementation Isolation Mechanism
NeoPythonComponent astrbot/core/computer/booters/shipyard_neo.py lines 32-41 Executes Python via self._sandbox.python.exec, running in the sandbox's isolated interpreter with limited memory and CPU.
NeoShellComponent astrbot/core/computer/booters/shipyard_neo.py lines 73-84 Executes shell commands via self._sandbox.shell.exec, confined to the container's namespace.
NeoFileSystemComponent astrbot/core/computer/booters/shipyard_neo.py lines 38-71 File operations via self._sandbox.filesystem, with paths resolved relative to the sandbox root.
NeoBrowserComponent astrbot/core/computer/booters/shipyard_neo.py lines 60-62 Only instantiated if the sandbox profile includes the browser capability.

Each component returns a structured dictionary containing success, stdout, stderr, and execution metadata, ensuring the host process never directly handles agent-generated data streams.

Local Mock Sandbox with Boxlite

For development environments or deployments without Docker access, BoxliteBooter in astrbot/core/computer/booters/boxlite.py provides a lightweight mock sandbox. It spins up a SimpleBox container and wraps it with MockShipyardSandboxClient, implementing the same RPC interface as the real Shipyard client.


# From boxlite.py lines 31-38 and 50-68

self.box = SimpleBox()
await self.box.start()
self.mock_client = MockShipyardSandboxClient(self.box)
self._sandbox = await self.mock_client.create_sandbox(profile=profile, ttl=ttl)

Even in this mock mode, agent code never touches the host filesystem directly. All reads and writes flow through the mocked sandbox client, preserving the isolation contract while enabling local testing.

Lifecycle Management and Health Checks

The sandbox lifecycle is strictly managed to prevent stale or compromised instances from processing agent requests.

Health Monitoring: The available() method probes sandbox health via self._sandbox.refresh(). If the status is "failed" or "expired", the booter reports the sandbox as unavailable, triggering creation of a fresh instance.


# From shipyard_neo.py lines 97-110

async def available(self) -> bool:
    if not self._sandbox:
        return False
    try:
        await self._sandbox.refresh()
        return self._sandbox.status not in ("failed", "expired")
    except Exception:
        return False

Graceful Shutdown: The shutdown() method destroys the sandbox via self._client.__aexit__(), but intentionally preserves the underlying Bay container for reuse across sessions. This balances security (sandbox state is wiped) with performance (container startup overhead is avoided).

Skill Synchronization: Before execution, computer_client._sync_skills_to_sandbox uploads the current skill bundle to the sandbox filesystem and rescans metadata inside the isolated environment. This ensures the agent operates on a consistent, isolated copy of the skill code.

How the Sandbox Protects the Host

AstrBot's Agent Sandbox implements defense in depth through multiple isolation mechanisms:

  • Process Isolation: Each sandbox runs in its own Docker container (Bay) or lightweight namespace (Boxlite), ensuring agent processes cannot access the AstrBot host process memory or PID namespace.
  • Filesystem Isolation: Agents interact only with the sandbox's /workspace/ tree. The container's mount namespace prevents path traversal attacks that might escape to the host filesystem.
  • Capability Gating: Only capabilities explicitly declared in the sandbox profile (e.g., browser, filesystem) are exposed to the agent. Missing capabilities (network, GPU, raw sockets) are unavailable by default.
  • Time-to-Live (TTL): Sandboxes automatically expire after the configured TTL (default 3600 seconds), limiting the window for any persistent compromise or resource exhaustion attack.

Together, these layers ensure that even if an LLM agent generates malicious code, the execution is confined to a temporary, restricted environment that cannot affect the host system or other sessions.

Summary

  • AstrBot isolates agent code execution using sandboxed containers managed by pluggable booters like ShipyardNeoBooter and BoxliteBooter.
  • The Shipyard Neo integration creates fresh Docker-based sandboxes with configurable TTL, process isolation, and capability-based access controls.
  • Isolated components (NeoPythonComponent, NeoShellComponent, NeoFileSystemComponent, NeoBrowserComponent) ensure agent code never runs directly on the host.
  • Boxlite provides a lightweight mock sandbox for local development while maintaining the same isolation contract.
  • Health checks and lifecycle management prevent use of expired or failed sandboxes, with automatic cleanup and skill synchronization keeping environments fresh.

Frequently Asked Questions

How does AstrBot prevent sandbox escape vulnerabilities?

AstrBot relies on container-level isolation through Docker (for production) or lightweight namespaces (for testing). The sandbox runs in its own mount namespace, preventing filesystem escape, and has no access to the host's PID or network namespaces unless explicitly granted through capabilities. Additionally, the TTL expiration ensures that even if a sandbox is compromised, it has a limited lifetime.

What is the difference between Shipyard Neo and Boxlite booters?

Shipyard Neo is the production booter that connects to an external Bay service or launches local Docker containers to provide full isolation. Boxlite is a lightweight mock implementation intended for development and testing environments where Docker is unavailable. While Boxlite simulates the sandbox interface, it may not provide the same level of kernel-level isolation as Docker-based sandboxes.

Can I restrict which capabilities an agent has access to?

Yes. Capabilities are controlled through the shipyard_neo_profile configuration option. Each profile defines available capabilities such as browser, filesystem, shell, or python. The ShipyardNeoBooter only instantiates components for capabilities advertised by the sandbox (e.g., NeoBrowserComponent is only created if the browser capability exists). This prevents agents from accessing unapproved system resources.

How does the sandbox handle skill code synchronization?

Before executing agent tools, computer_client.py calls _sync_skills_to_sandbox to upload the current skill bundle to the sandbox's isolated filesystem via upload_file. It then rescans skill metadata inside the sandbox to update the UI-visible cache. This ensures the agent operates on a fresh, isolated copy of skills rather than accessing the host's skill directory directly.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →