Designing Secure Execution Sandboxes for Bash & Shell Tool Calls
Learn how to build secure sandboxes using Docker containers and system boundaries to run terminal commands safely via MCP.
Secure Execution Sandboxes for Bash & Shell Tool Calls
Giving an LLM agent access to run shell commands (/bin/bash or cmd.exe) directly on your host machine is a critical security vulnerability. An agent could accidentally rm -rf important directories, leak environment variables, or download malicious software via arbitrary curl commands.
Prerequisites
- ▸Docker Desktop or the Docker Engine installed and running on your host machine.
- ▸Node.js installed to wrap the Docker execution in an MCP server.
Architecture of a Sandboxed MCP Execution Server
To run bash scripts safely, execute the commands within an isolated Docker container configured with CPU constraints, strict memory limits, and no host network bridge:
[MCP Client] --> [Bash MCP Server] --> [Spawns Ephemeral Docker Container]
|
+---> CPU Limit: 0.5 Cores
+---> Memory Limit: 512MB
+---> Read-Only Host Mounts
+---> No Internet BridgeNode.js Docker-based Shell Execution Script
Here is an example TypeScript implementation of a tool that accepts an agent's shell command and safely executes it inside an Alpine Linux sandbox:
import { exec } from 'child_process';
import util from 'util';
const execPromise = util.promisify(exec);
async function runCommandInSandbox(userCommand: string): Promise<string> {
// Deep sanitization is still necessary to prevent command injection into the Docker CLI itself
const sanitized = userCommand.replace(/'/g, "'\\''");
const dockerCmd = `docker run --rm \
--network none \
--memory 512m \
--cpus 0.5 \
alpine:latest sh -c '${sanitized}'`;
try {
const { stdout, stderr } = await execPromise(dockerCmd, { timeout: 10000 });
return stdout || stderr;
} catch (err: any) {
return `Execution Error: ${err.message}`;
}
}Best Practices
- ▸Drop Network Access: By using
--network none, you guarantee the agent cannotcurlorwgetexternal scripts, blocking potential data exfiltration or malware downloads. - ▸Ephemeral Containers: The
--rmflag ensures the container is immediately destroyed after the command finishes. State should not persist between tool calls. - ▸Hard Timeouts: Enforce a strict timeout (e.g., 10 seconds) so the agent cannot write an infinite
while trueloop that hogs host resources.
Troubleshooting
- ▸
docker: command not found: Ensure the Docker daemon is running and thedockerCLI is in thePATHof the environment executing the MCP server. - ▸Files Not Found: Since the execution happens in an isolated Alpine container, it has no access to your host filesystem. If you want the agent to read local files, you must explicitly bind-mount them using
-v /path/to/host:/app:ro(read-only!).
Related Guides
How to Build a Custom MCP Server from Scratch
Learn how to create your own MCP server using the TypeScript or Python SDK. Expose custom tools and resources for AI agents to use.
Dev ToolsHow to Use the Puppeteer MCP Server for Web Scraping & Automation
Automate web browsers using the Puppeteer MCP server. Navigate websites, take screenshots, extract data, and automate web interactions through AI.
Dev ToolsHow to Use the Git MCP Server for Version Control Operations
Manage local Git repositories through AI agents. Clone repos, create branches, make commits, and view diffs using the Git MCP server.