# Risk map — langgenius/dify

> Canonical page: https://codevetter.com/unpack/dify/risk-map

# Risk map — langgenius/dify

Scanned commit 3a017e8cccb316f23f601af65d2e8ce92e68f788 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The highest-risk surface is execution of untrusted work: SSRF-bearing HTTP egress, sandboxed code execution, shell job runtime with Landlock, and plugin-daemon RPC — all defended in depth but dependent on every caller routing through the right proxy. Auth is layered (session JWT, passport JWT, API tokens, shared inner-api key) with enterprise license gating able to fail closed across nearly every surface. Fragile spots: committed static test secrets, `ignoreBuildErrors` on the web build, a giant ordered extension-init list, and tenant-scoping discipline enforced by convention.
- SSRF is a designed-in risk domain: generic outbound HTTP must route through `core/helper/ssrf_proxy.py` (Squid at `SSRF_PROXY_*_URL`, `docker/ssrf_proxy/squid.conf.template`); remote file retrieval is split into `core/file/remote_fetcher` — any future code path using raw httpx bypasses egress policy. — [api/core/helper/ssrf_proxy.py#L1-13](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/helper/ssrf_proxy.py#L1-L13) [docker/ssrf_proxy](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/docker/ssrf_proxy) [api/AGENTS.md](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/AGENTS.md)
- Sandboxed execution: `dify-sandbox` is a separate container image for code nodes; `dify-agent-runtime` executes user shell jobs via tmux with Landlock filesystem restrictions — but `landlock_stub.go` implies no sandbox on non-Linux kernels, so dev/other-OS runs are unsandboxed. — [docker/docker-compose.yaml#L511](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/docker/docker-compose.yaml#L511) [dify-agent-runtime/internal/landlock/landlock_linux.go](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/dify-agent-runtime/internal/landlock/landlock_linux.go) [dify-agent-runtime/internal/landlock/landlock_stub.go](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/dify-agent-runtime/internal/landlock/landlock_stub.go) [dify-agent-runtime/cmd/runner/main.go#L1-16](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/dify-agent-runtime/cmd/runner/main.go#L1-L16)
- The entire `/inner/api` enterprise/plugin control plane hangs on one shared secret: `X-Inner-Api-Key` string-equality against `dify_config.INNER_API_KEY`, gated by the `INNER_API` flag (404 when off) — key rotation/leak blast radius covers workspace, agent, knowledge, and runtime-credentials endpoints. — [api/controllers/inner_api/wraps.py#L17-37](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/controllers/inner_api/wraps.py#L17-L37) [api/controllers/inner_api](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/controllers/inner_api)
- Enterprise license failure is fail-closed across `/console/api`, `/api`, `/v1`, `/mcp`, `/triggers`: unverifiable license (`None` on exception) produces the same denial as INACTIVE/EXPIRED/LOST — a license-service outage can take down the whole product except `/files`, `/inner/api`, `/health`. — [api/app_factory.py#L51-94](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/app_factory.py#L51-L94) [api/app_factory.py#L120-130](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/app_factory.py#L120-L130)
- Committed secret-shaped values in `api/pytest.ini` (PLUGIN_DAEMON_KEY, INNER_API_KEY_FOR_PLUGIN, ANTHROPIC/OPENAI keys) are test fakes but are static, long-lived, and grep-visible — risk of pattern-copy into real envs. (inferred) — [api/pytest.ini](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/pytest.ini)
- Web production builds cannot fail on type errors: `next.config.ts` sets `typescript.ignoreBuildErrors: true`; correctness relies on separate lint/type-check CI steps staying green. — [web/next.config.ts#L21-23](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/web/next.config.ts#L21-L23)
- Tenant isolation is enforced by convention, not framework: AGENTS.md mandates propagating `tenant_id` across every layer and re-scoping reads by 'the complete owner chain', and `decode_jwt_token`/`AppExecutionParams` rehydrate entities from DB after trust boundaries — a missed `tenant_id` filter in any new service method is a cross-tenant data leak. — [api/AGENTS.md](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/AGENTS.md) [api/controllers/web/wraps.py#L58-70](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/controllers/web/wraps.py#L58-L70) [api/tasks/app_generate/workflow_execute_task.py#L85-120](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/tasks/app_generate/workflow_execute_task.py#L85-L120)
- Celery payloads carry user ids and raw `args` through the Redis broker (`AppExecutionParams.model_dump_json()`); broker access reveals tenant inputs, and non-idempotent retried tasks would double side effects — AGENTS.md requires idempotency and bounded transactions (no external I/O inside open DB transactions). — [api/services/app_generate_service.py#L252-265](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/services/app_generate_service.py#L252-L265) [api/AGENTS.md](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/AGENTS.md)
- Route enumeration is a known concern: `RESTX_ERROR_404_HELP` is explicitly disabled because flask-restx appends URL-map suggestions to 404 bodies; `controllers/console/spec.py` and the `/openapi` blueprint expose generated specs (OPENAPI_ENABLED gated). — [api/app_factory.py#L107-111](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/app_factory.py#L107-L111) [api/controllers/console/spec.py](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/controllers/console/spec.py) [api/extensions/ext_blueprints.py#L48-63](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/ext_blueprints.py#L48-L63)
- The ordered `initialize_extensions` list is fragile coupling: init order is load-bearing (key_provider after storage, logstore before celery, blueprints after everything) and an `is_enabled()` skip can silently drop a dependency of a later ext. (inferred) — [api/app_factory.py#L214-259](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/app_factory.py#L214-L259)
- Blocking-vs-streaming asymmetry: Agent App (`AppMode.AGENT`) is SSE-only — `response_mode='blocking'` raises 400 — and debug single-node/loop runs execute in the request process, so a runaway node can pin a web worker greenlet. — [api/controllers/web/completion.py#L45-51](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/controllers/web/completion.py#L45-L51) [api/services/app_generate_service.py#L391-434](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/services/app_generate_service.py#L391-L434)
- Webapp auth has layered token semantics (`token_source`, `auth_type`, `granted_at` SSO-staleness checks against external/workspace SSO update timestamps); regressions in `_validate_user_accessibility` silently lock out or over-admit end users. — [api/controllers/web/wraps.py#L105-163](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/controllers/web/wraps.py#L105-L163)
- Credential confidentiality depends on `ext_key_provider`'s RSAKeyProvider (reads private keys from object storage at boot) and the optional `kms` dependency group (azure-keyvault); storage misconfiguration at startup poisons all credential decryption. — [api/extensions/ext_key_provider.py](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/ext_key_provider.py) [api/app_factory.py#L228](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/app_factory.py#L228) [api/pyproject.toml#L192-198](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/pyproject.toml#L192-L198)
- Dead/legacy surfaces exist: `AppMode.CHANNEL`/`RAG_PIPELINE` are explicitly rejected by generation paths; `agent-chat` is documented as the legacy ReAct app superseded by `agent`; `tasks/collect_agent_resources_task.py` is marked 'retired' yet still imported by the worker. — [api/models/model.py#L374-385](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/models/model.py#L374-L385) [api/services/app_generate_service.py#L431-434](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/services/app_generate_service.py#L431-L434) [api/extensions/ext_celery.py#L175](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/ext_celery.py#L175)
- The editable cross-package dep `dify-agent = { path = "../dify-agent" }` means api version compatibility with the agent package is unpinned inside the lock beyond the workspace — drift between api and dify-agent breaks agent apps at runtime. (inferred) — [api/pyproject.toml#L62-64](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/pyproject.toml#L62-L64) [dify-agent/pyproject.toml](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/dify-agent/pyproject.toml)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
