Skip to content

Missing dedicated agent SSRF proxy for localSandbox (present in Dify 1.16.1+ docker-compose) #453

Description

@ZhXZhao

Summary

Chart 0.38.0 (appVersion: "1.16.1") ships the Agent v2 components agentBackend and localSandbox, but omits the dedicated SSRF proxy for the local sandbox (agent_ssrf_proxy in the upstream docker-compose.yaml).

As a result, the localSandbox pod receives no proxy configuration at all, and its egress/east-west traffic is completely unrestricted.

Upstream reference

agent_ssrf_proxy was introduced in Dify 1.16.1 — which is exactly the appVersion targeted by chart 0.38.0:

Dify version local_sandbox agent_backend agent_ssrf_proxy
1.16.0 yes yes no
1.16.1 yes yes yes
1.17.0 yes yes yes

In docker/docker-compose.yaml it is a distinct service from the existing ssrf_proxy:

  • image ubuntu/squid:latest, HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
  • uses its own squid template ./ssrf_proxy/squid-agent.conf.template (not the same as squid.conf.template used by ssrf_proxy)
  • attached to two networks: default and local_sandbox_proxy_network
  • local_sandbox_proxy_network is an internal bridge shared only by agent_ssrf_proxy and local_sandbox, so that the sandbox can reach squid without gaining a direct route to api (per the comments in the compose file)
  • local_sandbox sets HTTP_PROXY=http://agent_ssrf_proxy:3128, HTTPS_PROXY=http://agent_ssrf_proxy:3128, NO_PROXY=localhost,127.0.0.1

Current chart behavior

grep -rniE 'agent[-_]?ssrf' . over the repository returns zero matches.

The chart has a single ssrfProxy component, wired to two consumers only:

Consumer Variables Source
api / worker SSRF_PROXY_HTTP_URL, SSRF_PROXY_HTTPS_URL charts/dify/templates/config.tpl:80-82
sandbox HTTP_PROXY, HTTPS_PROXY charts/dify/templates/config.tpl:540-542 (in dify.sandbox.config)
localSandbox none —

charts/dify/templates/local-sandbox-config.yaml renders an empty ConfigMap (data: {}), and the local sandbox Secret only carries SHELLCTL_AUTH_TOKEN.

Reproduction

helm template my-dify ./charts/dify \
  --set localSandbox.enabled=true \
  --set agentBackend.enabled=true \
  --set ssrfProxy.enabled=true \
  | grep -E 'HTTP_PROXY|HTTPS_PROXY|NO_PROXY|SSRF_PROXY_HTTP_URL'

Observed (chart 0.38.0):

my-dify-api:      SSRF_PROXY_HTTP_URL: http://my-dify-ssrf-proxy:3128
my-dify-sandbox:  HTTP_PROXY:  http://my-dify-ssrf-proxy:3128
my-dify-sandbox:  HTTPS_PROXY: http://my-dify-ssrf-proxy:3128

Nothing is emitted for my-dify-local-sandbox.

Impact

Upstream achieves the isolation through Docker internal networks. There is no equivalent in the chart, and the chart also ships no NetworkPolicy template (grep -rl NetworkPolicy charts/dify/templates/ -> no match; rendered output contains only ConfigMap / Deployment / Ingress / Job / PVC / Secret / Service).

So agent-generated code running inside localSandbox currently:

  • reaches the internet directly, bypassing any forward proxy and its ACLs
  • can reach the api / agent-backend / plugin-daemon Services directly, which upstream explicitly prevents
  • can reach any other in-cluster pod IP, plus external PostgreSQL / Redis / object storage endpoints configured for the release

This is a meaningful weakening of the upstream threat model for a component whose entire purpose is executing untrusted code.

Note also that the existing ssrfProxy squid config is not a drop-in substitute: dify.ssrfProxy.config.squid ends with a Reverse Proxy To Sandbox block (http_port <sandbox port> accel vhost + cache_peer to the code sandbox, with acl src_all src all / http_access allow src_all), which is not what the upstream agent-specific template does.

Suggested fix

  1. Add an agentSsrfProxy component (deployment / service / configmap / serviceaccount) with its own squid config mirroring upstream squid-agent.conf.template, guarded by localSandbox.enabled.
  2. Inject HTTP_PROXY / HTTPS_PROXY / NO_PROXY into the localSandbox ConfigMap pointing at it.
  3. Optionally ship an opt-in NetworkPolicy to approximate local_sandbox_proxy_network / agent_sandbox_network: allow localSandbox egress only to agentSsrfProxy:3128 and DNS, and allow ingress to localSandbox:5004 only from agentBackend. Without this, step 1 restores proxied egress but not the east-west isolation.

Workaround

Point the local sandbox at the existing proxy via extraEnv (does not address east-west isolation):

localSandbox:
  extraEnv:
    - name: HTTP_PROXY
      value: "http://<release>-ssrf-proxy:3128"
    - name: HTTPS_PROXY
      value: "http://<release>-ssrf-proxy:3128"
    - name: NO_PROXY
      value: "localhost,127.0.0.1"

Environment

  • Chart: 0.38.0 (appVersion: "1.16.1"), also reproduced against 1.17.0 images
  • Helm: v4.2.4

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions