Documentsdify
Sandbox Network Isolation
Sandbox Network Isolation
Type
Topic
Status
Published
Created
Jul 7, 2026
Updated
Jul 7, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Sandbox Network Isolation#

Dify's sandbox environment routes all outbound HTTP/S traffic through a Squid-based SSRF proxy. As of Dify 1.15.0, this proxy enforces a deny-by-default policy that blocks all private/RFC-1918 IP ranges and only allows .marketplace.dify.ai out of the box. Workflows or HTTP-request nodes that call internal services will return TCP_DENIED/403 after upgrading from earlier versions.


Network Topology#

Docker Compose defines a dedicated internal bridge network named ssrf_proxy_network with internal: true. This means containers on that network cannot reach the Docker host's external network directly; all egress must traverse the proxy.

┌─ default network (external access) ─────────────┐
│ nginx ←──→ api / worker / plugin_daemon │
└──────────────────────────────────────────────────┘
                    │ ssrf_proxy_network (internal)
              ssrf_proxy (Squid :3128)
              sandbox (port 8194)

Services that join both networks (api, worker, worker_beat, plugin_daemon) can reach the Squid proxy for outbound calls while still communicating with the rest of the stack on the default network . The sandbox service joins only ssrf_proxy_network and is intentionally cut off from the default network .

The sandbox container is pre-configured to send all traffic through the proxy via HTTP_PROXY and HTTPS_PROXY environment variables :

HTTP_PROXY: http://ssrf_proxy:3128
HTTPS_PROXY: http://ssrf_proxy:3128

Service-name DNS resolution (e.g., ssrf_proxy) works because Docker's embedded DNS resolver is available to every container in a shared network — including the internal: true ssrf_proxy_network.


Squid Deny-by-Default Policy#

The proxy configuration in docker/ssrf_proxy/squid.conf.template enforces the following access control order:

  1. Include override file first/etc/squid/dify_allow_private.conf is evaluated before any deny rules , so environment-variable-based exceptions always win.
  2. Allow static allowlistacl allowed_domains dstdomain .marketplace.dify.ai is the only hardcoded outbound domain .
  3. Block private IPs — the to_private_networks ACL covers 14 ranges :
    0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16, 224.0.0.0/4, 240.0.0.0/4, plus IPv6 equivalents (::1/128, fc00::/7, fe80::/10, etc.)
  4. Deny everything elsehttp_access deny all as the final rule .

Adding Exceptions#

The docker/ssrf_proxy/docker-entrypoint.sh reads two .env variables at startup and generates Squid ACL fragments into /etc/squid/dify_allow_private.conf :

VariableEffect
SSRF_PROXY_ALLOW_PRIVATE_DOMAINSAllows named hosts/domains that resolve to private IPs (comma-separated)
SSRF_PROXY_ALLOW_PRIVATE_IPSAllows specific private IPs or CIDR ranges (comma-separated)

These are also exposed as environment pass-throughs in the ssrf_proxy service definition .

Example .env additions:

SSRF_PROXY_ALLOW_PRIVATE_DOMAINS=internal.mycompany.com
SSRF_PROXY_ALLOW_PRIVATE_IPS=10.10.5.42,192.168.1.0/24

After editing .env, restart the proxy: docker compose restart ssrf_proxy (or down/up to regenerate configs).


API-Layer SSRF Detection#

api/core/helper/ssrf_proxy.py routes all outbound requests through the Squid proxy via configurable proxy mounts . When Squid blocks a request and returns a 401 or 403, the code checks for squid in the Server or Via response header and raises ToolSSRFError . No local DNS or IP validation is performed — all enforcement is delegated to the proxy.


Key Files#

FilePurpose
docker/docker-compose.yamlDefines ssrf_proxy_network and which services join it
docker/ssrf_proxy/squid.conf.templateSquid ACL rules and deny-by-default policy
docker/ssrf_proxy/docker-entrypoint.shGenerates runtime ACL fragments from env vars
api/core/helper/ssrf_proxy.pyAPI-layer proxy routing and ToolSSRFError detection
Sandbox Network Isolation | Dosu