Skip to main content
isol8 is designed to run untrusted code safely. Every execution is isolated in a Docker container with multiple layers of defense.

Container Isolation

Each execution runs inside a Docker container with the following security constraints:
ControlDefaultConfigurable
Read-only root filesystemEnabled--writable / readonlyRootFs: false
No network accessnone--net host|filtered / network
Memory limit512 MB--memory / memoryLimit
CPU limit1 core--cpu / cpuLimit
PID limit64--pids-limit / pidsLimit
Sandbox tmpfs512 MB--sandbox-size / sandboxSize
Tmp tmpfs256 MB--tmp-size / tmpSize
no-new-privilegesEnabledNot configurable
Non-root user (sandbox)EnabledNot configurable
Execution timeout30 seconds--timeout / timeoutMs

Container Filesystem

Containers use two tmpfs mounts for security and performance:

/sandbox (default: 512 MB)

  • Purpose: Working directory for code execution
  • Mount flags: rw,exec,nosuid,nodev
  • Contents:
    • User code files
    • Package installations (.local, .npm-global, .bun-global)
    • User-created files and outputs
  • Execution: Allowed (required for native extensions like numpy’s .so files)
  • Configurable via: --sandbox-size CLI flag or sandboxSize config option

/tmp (default: 256 MB)

  • Purpose: Temporary files and caches
  • Mount flags: rw,noexec,nosuid,nodev
  • Contents:
    • Temporary files created by programs
    • Package manager caches during installation
  • Execution: Disabled (noexec flag) for security
  • Configurable via: --tmp-size CLI flag or tmpSize config option
Packages installed with --install are stored in /sandbox (not /tmp) because they often contain shared libraries (.so files) that need to be executable. The /tmp mount has the noexec flag which would prevent these libraries from loading.

Network Control

none (Default)

The container has no network access. No DNS, no HTTP, no TCP — nothing leaves the container.

host

Full host network access. Use only when you trust the code or need unrestricted connectivity.

filtered

Bridge network with an HTTP/HTTPS proxy (proxy.mjs) that filters requests by hostname:
  • Whitelist — Only matching hostnames are allowed (regex patterns)
  • Blacklist — Matching hostnames are blocked (regex patterns)
# Allow only OpenAI and GitHub APIs
isol8 run script.py --net filtered \
  --allow "^api\.openai\.com$" \
  --allow "^api\.github\.com$"
The proxy intercepts HTTP and HTTPS traffic via HTTP_PROXY/HTTPS_PROXY environment variables. The container can only reach external hosts through the proxy.

Secret Masking

Secrets passed via --secret KEY=VALUE (CLI) or secrets: { KEY: "VALUE" } (library) are:
  1. Injected into the container as environment variables
  2. Automatically masked in all output (stdout and stderr)
Any occurrence of the secret value in the output is replaced with ***.
isol8 run -e "import os; print(os.environ['API_KEY'])" \
  --runtime python --secret API_KEY=sk-1234
# stdout: ***
This prevents accidental leakage of credentials in logs, AI agent responses, or user-facing output.

Output Truncation

Output is truncated to maxOutputSize (default 1 MB) to prevent memory exhaustion from programs that produce excessive output. When truncation occurs, ExecutionResult.truncated is set to true.

Timeout Enforcement

When a timeout is reached:
  1. The process inside the container is killed (via timeout shell wrapper)
  2. "EXECUTION TIMED OUT" is appended to stderr
  3. The container is cleaned up (ephemeral) or preserved minus the killed process (persistent)
This prevents runaway code from consuming resources indefinitely.

Docker Image Security

Base images are built from a multi-stage Dockerfile with:
  • Alpine Linux base (minimal attack surface)
  • Non-root sandbox user
  • Only the runtime binary and essential dependencies
  • Proxy script for filtered networking
Custom images (isol8 setup --python numpy) extend the base image with additional packages but maintain the same security posture.

Best Practices

1

Use network: none by default

Only enable network access when the code genuinely needs it. Most code execution tasks don’t require network.
2

Use filtered mode with tight allowlists

When network is needed, prefer filtered with explicit --allow patterns rather than host mode.
3

Set appropriate resource limits

Lower memory, CPU, and PID limits to the minimum your workload needs.
4

Use secrets for credentials

Never embed API keys in code strings. Use --secret to inject them as masked env vars.
5

Use ephemeral mode

Prefer ephemeral execution for one-off tasks. Persistent mode should only be used when state preservation is genuinely needed.
6

Keep timeout low

Set timeouts appropriate to your workload. 30 seconds is generous for most tasks.