Understanding the Claude Code sandbox security model
This document describes the sandboxing architecture implemented to isolate Claude Code from sensitive system executables while allowing the main application to retain full access to these tools.
Claude Code needs to run in a secure environment where it cannot:
However, Claude Code SHOULD be able to:
rm, curl, wget for file operations and downloadsMeanwhile, the Next.js application must:
Docker Container
| Next.js App | Claude Code (Git Sandboxed) |
|---|---|
Uses: /opt/internal/bin/git ✓ | Blocked: git (wrapper) ✗ |
| Standard tools: rm ✓, curl ✓, wget ✓ | Accessible: rm ✓, curl ✓, wget ✓, npm ✓ |
Location: /Dockerfile (lines 20-31)
During Docker build:
/opt/internal/bin/git/usr/bin/gitSANDBOX SETUP: Isolate git from Claude Code - only block git access since Claude Code needs rm, curl, wget for operations:
RUN mkdir -p /opt/internal/bin \
&& mv /usr/bin/git /opt/internal/bin/git \
&& chmod 755 /opt/internal/bin/git
Create blocking wrapper script for git only:
RUN echo '#!/bin/bash\necho "[BLOCKED] git access denied"\nexit 1' > /usr/bin/git \
&& chmod 755 /usr/bin/git
Result:
/usr/bin/git but it's a blocking scriptrm, curl, wget normally/opt/internal/bin/git for all git operationsLocation: /claude-code-wrapper.sh
A bash script that:
Usage:
/usr/local/bin/claude-code-wrapper /app/workspaces/my-project [args...]
Security Features:
PATH restricted to /usr/local/bin:/bin:/usr/bin (no /opt/internal/bin)GIT_CONFIG_* variables nullifiedLocation: /src/lib/git/sandbox.ts
TypeScript module that:
simple-git to use /opt/internal/bin/gitcreateSandboxedGit() functionKey Functions:
// Create git instance with internal binary
const git = createSandboxedGit('/app/workspaces/repo');
// Get path to internal executable
const gitPath = getInternalExecutable('git');
// Check if sandbox is enabled
const isSandbox = isSandboxEnabled();
Location: /src/lib/git/core.ts
All git operations in the application use the sandboxed git instance:
import { createSandboxedGit } from '@/lib/git/sandbox';
function createGitInstance(workingDirectory?: string): SimpleGit {
return createSandboxedGit(workingDirectory || process.cwd());
}
Location: /src/lib/claudeCode/orchestrator.ts
Uses the sandbox wrapper with defaults defined in code:
const wrapperPath = process.env.CLAUDE_CODE_WRAPPER || '/usr/local/bin/claude-code-wrapper';
const command = `${wrapperPath} ${workspacePath} --verbose -p "..."`;
User initiates Claude Code request → API endpoint
Application calls askClaudeCode(question, options)
Spawns process using wrapper:
/usr/local/bin/claude-code-wrapper /app/workspaces/repo -p "question"
Wrapper script:
claude-code with argsClaude Code attempts to run git command
PATH lookup finds /usr/bin/git (blocking wrapper)
Wrapper returns error: [BLOCKED] git access denied
Claude Code cannot perform git operations ✓
Application code needs to clone repo
Calls cloneRepository(url, path)
Function uses createGitInstance(path)
Creates sandboxed git instance:
return simpleGit({ binary: '/opt/internal/bin/git' });
simple-git library calls /opt/internal/bin/git directly
Real git binary executes successfully ✓
rm, mv, etc.curl, wget/opt/internal/bin//usr/bin/git returns error/opt/internal/bin excluded from Claude's PATHsimple-git configured with internal binary pathThe sandbox security is automatically verified in every CI/CD pipeline run:
GitLab CI Pipeline Stage: docker-test
Job: docker-sandbox-verify
This job:
Configuration: .gitlab-ci.yml lines 127-188
When it runs:
master or main branchView Results:
docker-test stagedocker-sandbox-verify jobSSH into container and test as nextjs user (Claude Code's context):
docker exec -it workflow-app bash
git --version
Expected: [BLOCKED] git access denied - use app API instead
Check application logs during repository clone:
docker logs workflow-app | grep CLAUDE
Should show: Using API key from runtime configuration
Should NOT show git blocking errors
docker exec -it workflow-app bash
/opt/internal/bin/git --version
Expected: git version 2.x.x
Run comprehensive automated tests:
docker exec workflow-app /app/scripts/verify-sandbox.sh
Symptom: Application logs show git errors
Check:
INTERNAL_GIT_PATH is set correctlyls -l /opt/internal/bin/git/opt/internal/bin/git --versionSymptom: Claude Code successfully runs git commands
Check:
docker exec workflow-app git --versionwhich claude-code-wrapperSymptom: Error: /usr/local/bin/claude-code-wrapper: No such file
Check:
docker-compose build --no-cachedocker exec workflow-app ls -l /usr/local/bin/claude-code-wrapperAdditional security measures
Resource limits (already in wrapper, can be enabled)
Audit logging
Fine-grained controls
Additional command isolation (if needed)
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2025-11-25 | Initial sandbox implementation |
Last Updated: 2025-11-25 Maintained By: Development Team