Skip to main content

Overview

Esprit runs security scans inside isolated Docker containers based on Kali Linux. You can customize the base image to include additional tools, configurations, or integrations specific to your environment.

Default Image

The official Esprit sandbox image is:
improdead/esprit-sandbox:latest
Built from: containers/Dockerfile

Base Image Architecture

The Esprit sandbox container includes:

Core Components

  • Base OS: Kali Linux Rolling (latest)
  • Python: 3.12+ with Poetry for dependency management
  • Security Tools: nmap, sqlmap, nuclei, ffuf, subfinder, httpx, and more
  • Browser: Chromium with Playwright for web application testing
  • Proxy: Caido for HTTP request/response interception
  • Runtime: Tool server for agent communication

User Configuration

USER pentester
WORKDIR /workspace
  • Non-root user: pentester (UID varies)
  • Working directory: /workspace
  • Home directory: /home/pentester

Network Capabilities

cap_add:
  - NET_ADMIN
  - NET_RAW
Required for raw socket operations (nmap, packet capture, etc.)

Building Custom Images

Method 1: Extend the Official Image

Create a custom Dockerfile:
FROM improdead/esprit-sandbox:latest

USER root

# Install additional tools
RUN apt-get update && apt-get install -y \
    your-custom-tool \
    another-tool \
    && rm -rf /var/lib/apt/lists/*

# Install Python packages
RUN /app/venv/bin/pip install \
    custom-python-package \
    another-package

# Install Go-based tools
USER pentester
RUN go install github.com/yourorg/custom-tool@latest

# Add custom scripts
COPY --chown=pentester:pentester scripts/ /home/pentester/custom-scripts/
RUN chmod +x /home/pentester/custom-scripts/*.sh

# Add custom wordlists
COPY wordlists/ /home/pentester/wordlists/

USER pentester
WORKDIR /workspace
Build and push:
docker build -t yourorg/esprit-custom:latest .
docker push yourorg/esprit-custom:latest

Method 2: Fork and Modify Base Dockerfile

Clone the Esprit repository and modify containers/Dockerfile:
git clone https://github.com/esprit-cli/Esprit.git
cd Esprit/containers
Modify the Dockerfile to add your customizations:
# After existing tool installations, add your own:
RUN apt-get update && apt-get install -y \
    custom-tool-1 \
    custom-tool-2 \
    && apt-get autoremove -y \
    && apt-get autoclean \
    && rm -rf /var/lib/apt/lists/*

# Add custom Go tools
USER pentester
RUN go install github.com/custom/tool@latest

# Install custom Python tools
RUN pipx install custom-security-tool
Build from the repository root:
cd ..
docker build -f containers/Dockerfile -t yourorg/esprit-sandbox:custom .

Image Customization Examples

Add Cloud Provider Tools

FROM improdead/esprit-sandbox:latest

USER root

# AWS CLI
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
    && unzip awscliv2.zip \
    && ./aws/install \
    && rm -rf aws awscliv2.zip

# Google Cloud SDK
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | \
    tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \
    && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
    apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - \
    && apt-get update && apt-get install -y google-cloud-cli

# Azure CLI
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash

USER pentester

Add Custom Wordlists

FROM improdead/esprit-sandbox:latest

USER pentester
WORKDIR /home/pentester/wordlists

# SecLists
RUN git clone --depth 1 https://github.com/danielmiessler/SecLists.git

# Custom wordlists
COPY --chown=pentester:pentester custom-wordlists/ ./custom/

WORKDIR /workspace

Add Mobile Testing Tools

FROM improdead/esprit-sandbox:latest

USER root

# Android SDK and tools
RUN apt-get update && apt-get install -y \
    android-sdk \
    adb \
    fastboot \
    && rm -rf /var/lib/apt/lists/*

# MobSF dependencies
RUN apt-get update && apt-get install -y \
    default-jdk \
    && rm -rf /var/lib/apt/lists/*

USER pentester

# Frida
RUN /app/venv/bin/pip install frida-tools objection

WORKDIR /workspace

Add API Testing Tools

FROM improdead/esprit-sandbox:latest

USER root

# Postman CLI (newman)
RUN npm install -g newman newman-reporter-htmlextra

# GraphQL tools
RUN npm install -g graphqurl @apollographql/rover

USER pentester

# Python API testing tools
RUN /app/venv/bin/pip install \
    httpx-cli \
    mitmproxy \
    postman-to-openapi

WORKDIR /workspace

Add Custom CA Certificates

FROM improdead/esprit-sandbox:latest

USER root

# Copy custom CA certificates
COPY corporate-ca.crt /usr/local/share/ca-certificates/
COPY internal-ca.crt /usr/local/share/ca-certificates/

# Update CA trust store
RUN update-ca-certificates

# Update Python certifi bundle
RUN cat /usr/local/share/ca-certificates/corporate-ca.crt >> /app/venv/lib/python3.12/site-packages/certifi/cacert.pem

USER pentester

Using Custom Images

Set via Environment Variable

export ESPRIT_IMAGE=yourorg/esprit-custom:latest
esprit scan https://example.com

Set via Configuration File

~/.esprit/cli-config.json:
{
  "env": {
    "ESPRIT_IMAGE": "yourorg/esprit-custom:latest"
  }
}

Per-Scan Override

ESPRIT_IMAGE=yourorg/esprit-custom:v1.2.3 esprit scan ./app

Multi-Architecture Support

Build for ARM64 and AMD64

# Set up buildx
docker buildx create --use

# Build multi-arch image
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t yourorg/esprit-sandbox:latest \
  --push \
  -f containers/Dockerfile .

Platform-Specific Optimization

FROM improdead/esprit-sandbox:latest

USER root

# Conditional installation based on architecture
RUN ARCH=$(uname -m) && \
    if [ "$ARCH" = "x86_64" ]; then \
        curl -L https://example.com/tool-amd64 -o /usr/local/bin/tool; \
    elif [ "$ARCH" = "aarch64" ]; then \
        curl -L https://example.com/tool-arm64 -o /usr/local/bin/tool; \
    fi && \
    chmod +x /usr/local/bin/tool

USER pentester

Image Size Optimization

Minimize Layers

# Bad: Multiple RUN commands
RUN apt-get update
RUN apt-get install -y tool1
RUN apt-get install -y tool2
RUN rm -rf /var/lib/apt/lists/*

# Good: Single RUN command
RUN apt-get update && apt-get install -y \
    tool1 \
    tool2 \
    && apt-get autoremove -y \
    && apt-get autoclean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

Use .dockerignore

Create .dockerignore in your build context:
.git
.github
__pycache__
*.pyc
.pytest_cache
.mypy_cache
node_modules
.env
*.log
dist
build

Multi-Stage Builds

# Build stage for compiling tools
FROM golang:1.21 AS builder
WORKDIR /build
RUN go install github.com/custom/tool@latest

# Runtime stage
FROM improdead/esprit-sandbox:latest
USER pentester
COPY --from=builder /go/bin/tool /home/pentester/go/bin/
WORKDIR /workspace

Verification and Testing

Test Custom Image Locally

# Build image
docker build -t esprit-custom:test .

# Test container startup
docker run --rm -it \
  -e TOOL_SERVER_PORT=48081 \
  -e TOOL_SERVER_TOKEN=test-token \
  -p 48081:48081 \
  esprit-custom:test

# Verify tools are installed
docker run --rm esprit-custom:test which your-custom-tool

# Check Python packages
docker run --rm esprit-custom:test \
  /app/venv/bin/pip list | grep your-package

Test with Esprit

# Use custom image for a test scan
ESPRIT_IMAGE=esprit-custom:test esprit scan https://example.com

Image Registry Configuration

Private Registry Authentication

# Login to private registry
docker login registry.example.com

# Use private image
export ESPRIT_IMAGE=registry.example.com/esprit-sandbox:latest
esprit scan https://example.com

Pull Through Cache

Configure Docker daemon (/etc/docker/daemon.json):
{
  "registry-mirrors": ["https://your-registry-mirror.example.com"]
}

CI/CD Integration

Build in GitHub Actions

name: Build Custom Sandbox

on:
  push:
    paths:
      - 'docker/Dockerfile'
      - 'docker/**'

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      
      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: docker/Dockerfile
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            yourorg/esprit-sandbox:latest
            yourorg/esprit-sandbox:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Automated Security Scanning

- name: Scan Image for Vulnerabilities
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: yourorg/esprit-sandbox:latest
    format: 'sarif'
    output: 'trivy-results.sarif'

- name: Upload Scan Results
  uses: github/codeql-action/upload-sarif@v2
  with:
    sarif_file: 'trivy-results.sarif'

Runtime Configuration

The Esprit runtime starts containers with specific configurations. See esprit/runtime/docker_runtime.py:161-180:
container = self.client.containers.run(
    image_name,
    command="sleep infinity",
    detach=True,
    ports={f"{CONTAINER_TOOL_SERVER_PORT}/tcp": self._tool_server_port},
    cap_add=["NET_ADMIN", "NET_RAW"],
    environment={
        "PYTHONUNBUFFERED": "1",
        "TOOL_SERVER_PORT": str(CONTAINER_TOOL_SERVER_PORT),
        "TOOL_SERVER_TOKEN": self._tool_server_token,
        "ESPRIT_SANDBOX_EXECUTION_TIMEOUT": str(execution_timeout),
    },
    extra_hosts={HOST_GATEWAY_HOSTNAME: "host-gateway"},
    tty=True,
)

Custom Environment Variables

You can pass additional environment variables by modifying the runtime configuration or using Docker environment files.

Troubleshooting

Image Pull Failures

# Check Docker daemon is running
docker info

# Test image pull manually
docker pull yourorg/esprit-custom:latest

# Check registry authentication
docker login yourorg.registry.com

Container Startup Issues

# Check container logs
docker logs esprit-scan-<id>

# Inspect container configuration
docker inspect esprit-scan-<id>

# Test entrypoint manually
docker run --rm -it yourorg/esprit-custom:latest /bin/bash

Tool Server Not Starting

Check the entrypoint script (containers/docker-entrypoint.sh:154-203):
# View entrypoint logs
docker exec esprit-scan-<id> cat /tmp/tool_server.log

# Verify tool server health
curl http://localhost:48081/health

Best Practices

  1. Version Tags - Always tag images with versions, not just latest
  2. Minimize Size - Remove unnecessary files and combine RUN commands
  3. Security Scanning - Scan custom images for vulnerabilities before use
  4. Reproducible Builds - Pin tool versions in Dockerfile
  5. Layer Caching - Order Dockerfile commands from least to most frequently changing
  6. Multi-Arch Support - Build for both ARM64 and AMD64 when possible
  7. Documentation - Document all custom tools and configurations added
  8. Testing - Test custom images locally before deploying to CI/CD

See Also

Build docs developers (and LLMs) love