Code Sandboxing
TeamWeb AI allows assistants to execute code during conversations using the execute_code tool. This is a powerful capability — assistants can write and run Python, JavaScript, Java, C++, Go, and R code to perform data analysis, generate files, create visualizations, and more. Sandboxing ensures this code runs safely without compromising the host system or accessing sensitive data.
How Sandboxing Works
When an assistant calls execute_code, the code runs inside an isolated Docker container — not in the main application process. Each conversation gets its own sandbox container that persists across multiple code executions within that conversation.
Container creation
The first time execute_code is called in a conversation, a new Docker container is created from the teamwebai-sandbox image. A Python virtual environment is set up inside the container, and working directories are created for output files and scripts.
Code execution
The assistant’s code is sent to the container and executed. The code runs as a normal process inside the container with access to pre-installed packages and any packages installed during the conversation.
Output collection
After execution completes, the system checks the /sandbox/output/ directory for any files the code created. These files are extracted from the container and saved as deliverables, accessible via the conversation’s content.
Container reuse
Subsequent execute_code calls in the same conversation reuse the same container. Installed packages, created files, and environment state persist across calls. The output directory is cleaned between agent loop iterations to prevent stale results.
The Sandbox Image
The sandbox container uses a python:3.12-slim base image pre-loaded with commonly used packages to avoid repeated installation:
| Category | Packages |
|---|---|
| Data | pandas, numpy, openpyxl, xlsxwriter |
| Visualization | matplotlib |
| Web scraping | requests, beautifulsoup4, lxml |
| Imaging | Pillow |
| Documents | reportlab |
| Utilities | pyyaml, tabulate |
Additional Python packages can be installed on the fly — the assistant detects import statements in the code, identifies packages that aren’t pre-installed, and runs pip install before execution.
Technical Details
Package auto-detection — Before executing Python code, the system parses the code’s abstract syntax tree (AST) to extract all import and from ... import statements. Each import is mapped to its PyPI package name (handling cases like PIL mapping to Pillow or bs4 mapping to beautifulsoup4). Pre-installed packages are filtered out, and the remaining packages are installed via pip in the container’s virtual environment. The virtual environment uses --system-site-packages so pre-installed packages from the base image are available alongside pip-installed ones.
Path rewriting — The system automatically rewrites file output paths in the code. If the assistant writes to a path like /sandbox/data.xlsx, it is rewritten to /sandbox/output/data.xlsx so the file can be collected after execution. This ensures generated files end up in the scanned output directory regardless of what path the code uses.
Container lifecycle — The container ID is stored in Redis with a key tied to the conversation ID. This allows the container to be reused across multiple Celery task invocations (e.g., when the user sends another message in the same conversation and the assistant runs code again). A background cleanup task runs every 5 minutes and removes containers that have been idle for more than 10 minutes.
Isolation Guarantees
The sandbox provides several layers of isolation to protect the host system and application data:
Network Isolation
Sandbox containers are not connected to the application network. They cannot reach the PostgreSQL database, Redis, or any other application service. The containers do have default Docker bridge networking, which may allow outbound internet access (for package installation and web requests in user code).
network_mode: none disables all networking entirely, including outbound internet access.Filesystem Isolation
- No application code — The
/appdirectory (TeamWeb AI’s source code) is not mounted - No configuration files — The
.envfile and application configuration are not available - No other plugins — The plugin directory is not mounted (except for sandboxable plugin tools, which mount only their own code as read-only)
- No Docker socket — The container cannot create other containers or interact with Docker
Credential Isolation
- No environment variables — The container receives only
PYTHONUNBUFFERED=1for proper output handling - No database credentials — The
DATABASE_URLand other connection strings are not passed - No API keys — LLM provider keys, channel tokens, and plugin secrets are not available inside the sandbox
Execution Limits
- Timeout — Each code execution has a 30-second timeout. If the code doesn’t complete within that window, execution is terminated and an error is returned to the assistant
- Container lifetime — Containers are automatically cleaned up after 10 minutes of inactivity by a background task
Skill Scripts in the Sandbox
When an assistant has activated a skill that includes script files and then runs execute_code, the skill’s files are automatically copied into the sandbox container at /sandbox/scripts/. This allows the assistant to reference and execute skill scripts from within the sandbox.
Technical Details
Copy mechanism — Skill files are copied into the container using the Docker API’s file upload mechanism (tar archive to container). This is done once per agent loop — when the first execute_code call occurs and the conversation has activated skills. Binary files (images, fonts, PDFs) are transferred as-is, while text files are encoded appropriately. Script files are made executable with chmod +x after copying.
Scope — Only files from skills that have been explicitly activated during the conversation (via activate_skill) are copied. The assistant cannot access files from skills that are assigned to it but not yet activated.
Sandboxable Plugin Tools
Beyond execute_code, the plugin system supports running entire tool plugins inside sandboxed containers. When a plugin’s manifest sets sandboxable=True, its execute() method runs in a Docker container rather than in the main worker process.
How It Works
- The system generates a self-contained Python script that imports the tool class from the plugin code, instantiates it, and calls
execute()with the provided parameters - The plugin’s directory is mounted read-only at
/plugininside the container - The tool receives a
SandboxToolContextinstead of a fullToolContext— a lightweight data object with only basic information (project name, assistant name, user email, plugin config) - The result is returned as JSON on stdout
Restrictions
Sandboxable plugin tools have the strictest isolation of any execution environment in TeamWeb AI:
| Restriction | Code Execution (execute_code) | Sandboxable Plugin Tools |
|---|---|---|
| Network | Default bridge (outbound possible) | Completely disabled (none) |
| Filesystem | Empty container | Plugin code mounted read-only |
| Database access | None | None |
| API credentials | None | Plugin config only (no app config) |
| Timeout | 30 seconds | 30 seconds |
| Service access | None | None (no knowledge service, media service, or DB session) |
Technical Details
Context serialization — The ToolContext used in normal (non-sandboxed) execution contains live database sessions, service objects, and Flask application state that cannot be passed into a container. For sandboxed execution, the system serializes a minimal subset into a plain dictionary: project ID and name, conversation ID, assistant ID and name, user ID and email, and the plugin’s configuration. The app_config field is passed as an empty dictionary — no infrastructure secrets cross the sandbox boundary.
SandboxToolContext — Inside the container, the serialized data is loaded into a SandboxToolContext dataclass. This provides the same interface names as ToolContext (so plugin code can reference ctx.project, ctx.assistant, etc.) but the values are plain dictionaries rather than SQLAlchemy model instances. Methods that require database access (like ctx.log_api_call()) are not available.
Plugin base class availability — The BaseTool and SandboxToolContext classes are imported from a base.py file inside the container. This file is part of the sandbox image, providing just the class definitions needed for tool execution without the full application codebase.