Sandbox Code Execution#
Dify runs two distinct sandboxed execution environments in separate containers:
| Sandbox | Image | Port | Use case |
|---|---|---|---|
| dify-sandbox (legacy) | langgenius/dify-sandbox:0.2.15 | 8194 | Code nodes in Workflows (Python3, JS, Jinja2) |
| dify-agent-runtime | langgenius/dify-agent-local-sandbox:1.17.1 | 5004 | Agent V2 shell jobs |
Both are declared in docker/docker-compose-template.yaml as the sandbox and local_sandbox services respectively.
Legacy dify-sandbox (Code Nodes)#
The legacy sandbox is an external Go service (langgenius/dify-sandbox) running image langgenius/dify-sandbox:0.2.15 . It accepts HTTP requests and secures each execution with two independent layers:
- Docker isolation β container-level network and filesystem separation
- seccomp BPF β a per-child-process kernel syscall filter defaulting to
ActKillProcessfor any unlisted syscall
Languages supported: Python3, Node.js, and Jinja2 (which runs as Python3 at runtime) .
Configuration is in docker/volumes/sandbox/conf/config.yaml: port 8194, max_workers: 4, enable_network: true, and an optional allowed_syscalls list for extending the seccomp whitelist . The WORKER_TIMEOUT env var (default 15s) and PIP_MIRROR_URL for a custom PyPI mirror are set in the compose file .
Dependency caching: the compose file mounts ./volumes/sandbox/dependencies:/dependencies , allowing pre-downloaded Python packages to survive container restarts.
API Layer Integration (CodeExecutor)#
The CodeExecutor class in api/core/helper/code_executor/code_executor.py is the single entry point for all code execution from the API layer.
- Endpoint:
CODE_EXECUTION_ENDPOINT(defaulthttp://sandbox:8194) βPOST /v1/sandbox/run - Auth:
X-Api-Keyheader usingCODE_EXECUTION_API_KEY - Timeouts: connect 10 s, read 60 s, write 10 s (configurable)
- Connection pooling:
httpx.Limitswith configurablemax_connections(default 100) andmax_keepalive_connections(default 20)
Call flow: execute_workflow_code_template() β language transformer's transform_caller() (wraps user code, serializes inputs as base64) β execute_code() β POST /v1/sandbox/run β response parsed by transform_response().
Language transformers:
| Transformer | Language sent to sandbox | Preload script |
|---|---|---|
Python3TemplateTransformer | python3 | None |
NodeJsTemplateTransformer | nodejs | None |
Jinja2TemplateTransformer | python3 | Yes β initializes Jinja2 env before user template runs |
dify-agent-runtime (Agent V2 Shell)#
The dify-agent-runtime (langgenius/dify-agent-local-sandbox:1.17.1) is a Go rewrite of the original Python shellctl package, built for Agent V2 shell job execution . It exposes shellctl serve --listen 0.0.0.0:5004 .
Build: a two-stage Dockerfile β a golang:1.26 builder compiles five Go binaries (shellctl, shellctl-runner, shellctl-sanitize-pty, shellctl-runner-exit, dify-agent) with CGO_ENABLED=0, then copies them into a python:3.12-slim-bookworm runtime image .
Pre-installed toolchain in the runtime image :
| Tool | Version |
|---|---|
| Python | 3.12 (base image) |
| Node.js | 24.20.0 |
| pnpm | 11.9.0 |
| uv | 0.8.9 |
| System tools | git, jq, tmux, ripgrep, openssh-client, procps, unzip, zip, less, curl |
Runtime dependency installation: Agent job configurations (DifyShellLayerConfig) can declare cli_tools with install_commands lists; these bootstrap scripts are executed by shellctl-runner when a workspace is first created . pip, uv, npm, and pnpm are all available in the container for these install steps.
Filesystem isolation (Landlock): each job runs with per-workspace path restrictions β read-write only to $HOME and the workspace directory (cwd); read-only to /usr, /bin, /lib, etc.; everything else denied . The workspace directory itself serves as both the command working directory and temporary storage space, with TMPDIR, TMP, and TEMP environment variables pointing directly to it. Requires Linux β₯ 5.13; disable via SHELLCTL_ENABLE_PATH_ISOLATION=false.
Environment variables:
SHELLCTL_AUTH_TOKENβ authentication token for the shellctl endpoint ; the Agent V2 backend connects viaDIFY_AGENT_SHELLCTL_ENTRYPOINTHTTP_PROXY=http://agent_ssrf_proxy:3128β routes HTTP traffic through the agent SSRF proxyHTTPS_PROXY=http://agent_ssrf_proxy:3128β routes HTTPS traffic through the agent SSRF proxyNO_PROXY=localhost,127.0.0.1β bypasses proxy for localhost traffic
Network isolation: local_sandbox is not connected to the default network. It is connected to two internal networks:
agent_sandbox_networkβ shared withagent_backend, allowsagent_backendto communicate with the shellctl endpoint on port 5004local_sandbox_proxy_networkβ shared only withagent_ssrf_proxy, provides proxy access for outbound traffic
This network isolation prevents direct access to internal services like api.
Traffic routing: All HTTP/HTTPS traffic (except localhost and 127.0.0.1) is automatically routed through agent_ssrf_proxy on port 3128. The proxy enforces strict access control:
- β
Allows
agent_backend/agent-stub/*endpoints - β
Allows
api/files/*endpoints (for signed upload/download URLs) - β Allows external internet access (e.g., to LLM APIs)
- β
Allows additional private IPs or domains configured via
SSRF_PROXY_ALLOW_PRIVATE_IPSandSSRF_PROXY_ALLOW_PRIVATE_DOMAINSenvironment variables - β Denies all other internal service access (default behavior when allowlist variables are not set)
Shellctl communication (agent_backend β local_sandbox:5004) uses the agent_sandbox_network directly.
Security considerations: The proxy and network isolation prevent SSRF attacks from malicious code running in the sandbox. Code executed in the sandbox cannot directly reach internal services. Access to the Dify API is restricted to the /files/* endpoint for signed file URLs only. Access to agent_backend is restricted to /agent-stub/* endpoints only. Known limitation: code in the sandbox can still reach agent_backend via the agent_sandbox_network, though the primary goal is preventing access to api and other services.
Key Source Files#
| File | Purpose |
|---|---|
api/core/helper/code_executor/code_executor.py | CodeExecutor β HTTP client, language dispatch, error handling |
dify-agent-runtime/docker/Dockerfile | dify-agent-runtime image build: Go binaries + Node.js/Python/uv toolchain |
docker/volumes/sandbox/conf/config.yaml | Legacy sandbox runtime config (port, workers, network, syscalls) |
docker/docker-compose-template.yaml | Both sandbox service definitions, volume mounts, env vars |
docker/ssrf_proxy/squid-agent.conf.template | Agent SSRF proxy Squid configuration (access control rules) |
| langgenius/dify-sandbox | External repo for the legacy sandbox (seccomp rules, Python/Node runtime) |