# Defense-in-Depth Score: Langflow

**Repo:** https://github.com/langflow-ai/langflow · **Commit:** `f9b283243d2fdd8502cb4ffd606c3058cff5017e` · **Reviewed:** 2026-10-03
**What it is:** Visual tool for building and deploying AI agents and workflows
**Category:** Agent Frameworks
**Scored configuration:** Local `uv pip install langflow` + `langflow run` with shipped defaults: localhost:7860, allow_custom_components=true, sandbox_backend=none, agentic_experience (Assistant) on, MCP auto-init on, telemetry on.
**Agent surface (default):** code execution yes · filesystem write yes · network egress yes · external credentials yes · persistent memory yes · untrusted input yes · third party extensions yes · sub agents yes · external communication yes

## Score: 3.0 / 10.0 (Minimal)

| # | Criterion | S | C | D | B | Raw | Cap | Score | Confidence |
|---|---|---|---|---|---|---|---|---|---|
| C1 | Identity & least privilege | L0 | L1 | L0 | L0 | 0.07 | — | **0.07** | High |
| C2 | Approval gates | L2 | L1 | L0 | L1 | 0.28 | C2-POWERBYPASS | **0.25** | Medium |
| C3 | Tool & action scoping | L2 | L2 | L2 | L1 | 0.45 | — | **0.45** | High |
| C4 | Code-execution isolation | L4 | L1 | L0 | L3 | 0.53 | G1 | **0.50** (alt) | High |
| C5 | Untrusted input blast radius | L0 | L0 | L0 | L0 | 0.00 | C5-WORSTCASE | **0.00** | High |
| C6 | Memory, context & configuration integrity | L1 | L1 | L2 | L1 | 0.30 | — | **0.30** | High |
| C7 | Third-party extensions | L0 | L0 | L0 | L2 | 0.10 | C7-RCELOAD | **0.10** | High |
| C8 | Secrets & sensitive-data protection | L2 | L2 | L1 | L1 | 0.40 | — | **0.40** | High |
| C9 | Audit & traceability | L2 | L2 | L2 | L1 | 0.45 | — | **0.45** | High |
| C10 | Limits & kill switch | L2 | L2 | L2 | L1 | 0.45 | — | **0.45** | High |


Run as the README shows, Langflow's default authentication is not locked down. Flows, agent tools, custom components and the built-in Assistant's generated code all run inside the server process, which holds every stored credential and the key that decrypts them. Defenses against server-side request forgery (SSRF) and file-path restriction are good and on by default. A microVM sandbox and per-tool human approval exist, but both are opt-in, and nothing limits what a prompt-injected agent can do with its tools.

## Critical gaps
- Flows run with server-wide authority over all stored credentials, and default authentication is not locked down. (ASI03; C1)
- The Assistant executes model-generated component code in-process with no approval gate. (ASI02, ASI09; C2) — [src/backend/base/langflow/agentic/services/assistant_service.py:1596-1599](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/agentic/services/assistant_service.py#L1596-L1599); [src/backend/base/langflow/agentic/helpers/validation.py:280-308](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/agentic/helpers/validation.py#L280-L308)
- Model-influenced Python runs in-process behind a self-described non-guaranteed filter; an escape reaches the DB, the secret key and all credentials. (ASI05; C4) — [src/lfx/src/lfx/utils/python_repl_security.py:39-40](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/utils/python_repl_security.py#L39-L40); [src/lfx/src/lfx/services/settings/groups/security.py:196-202](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L196-L202); [src/lfx/src/lfx/custom/validate.py:692](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/custom/validate.py#L692)
- A prompt-injected agent can exfiltrate data and take irreversible actions unattended; the only defence is a prompt line. (ASI01, LLM01; C5) — [src/lfx/src/lfx/base/agents/default_system_prompt.py:23](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/agents/default_system_prompt.py#L23); [src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py:59-66](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py#L59-L66)
- Startup auto-configures an unpinned `uvx mcp-proxy` MCP server per user, which runs the latest PyPI release without consent. (ASI04; C7) — [src/backend/base/langflow/api/utils/mcp/config_utils.py:510-515](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/api/utils/mcp/config_utils.py#L510-L515); [src/backend/base/langflow/api/v1/mcp_projects.py:1736](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/api/v1/mcp_projects.py#L1736)

## Criterion details

### C1 Identity & least privilege — 0.07 (high)

Started the way the README says (`langflow run`), default authentication is not locked down. Every flow, agent and custom component runs inside the server process with that process's full authority, including the database and the key that decrypts every user's stored credentials. The HTTP API checks that a user owns a flow, but the role-based authorization layer is off by default and needs a plugin.

- **S L0:** The default identity is not locked down, and component code runs with the server process's ambient authority over the DB, the secret key and the environment. — [src/lfx/src/lfx/custom/validate.py:692](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/custom/validate.py#L692) (verified)
  - *To reach the next level:* No dedicated, narrowly scoped identity for flow/agent execution; L1 needs at least a separate identity for running agents.
- **C L1:** Flow APIs apply an owner check (owner override, then optional plugin), and MCP stdio subprocesses get a scrubbed env, but in-process components and code reach credentials and the DB directly. — [src/backend/base/langflow/services/authorization/guards.py:533-544](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/authorization/guards.py#L533-L544); [src/lfx/src/lfx/base/mcp/util.py:2027](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/mcp/util.py#L2027); [src/lfx/src/lfx/services/settings/auth.py:293-296](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/auth.py#L293-L296) (verified)
  - *To reach the next level:* In-process components and custom code bypass the authorization layer; L2 needs every built-in tool to act through the scoped identity.
- **D L0:** Default authentication is not locked down. (verified)
  - *To reach the next level:* L1 needs a narrower default identity.
- **B L0:** A hijacked flow or escaped code runs in the process that holds every user's encrypted credentials and the Fernet key that decrypts them. — [src/backend/base/langflow/services/variable/service.py:661](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/variable/service.py#L661); [src/backend/base/langflow/services/auth/utils.py:446-449](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/auth/utils.py#L446-L449) (verified)
  - *To reach the next level:* Credentials for all users and services are reachable from the execution process; L1 needs blast radius limited below cross-tenant/all-service access.
- **Cap:** none

### C2 Approval gates — 0.25 (medium)

The Agent component has a per-tool human approval step: a reviewer can approve, edit or reject a pending tool call from the UI, and an authenticated flow-execute permission check guards the resume endpoint. It is off by default: a tool is gated only if the flow author picks approval actions for it, and none are picked by default. Nothing gates components that run directly in a flow, and nothing gates the built-in Assistant, which runs model-generated component code in-process to validate it. Assistant edits to a flow get a restore point, but external actions have no undo.

- **S L2:** When enabled, LangChain HumanInTheLoopMiddleware pauses the agent and the card shows the middleware's action description (tool name and args per the library default), with approve/edit/reject. — [src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py:84-90](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py#L84-L90); [src/lfx/src/lfx/components/models_and_agents/agent.py:667-669](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent.py#L667-L669) (inferred)
  - *To reach the next level:* No risk tiers or argument-level policy, and the card shows only the first action's description; L3 needs per-call display of every exact call with risk tiers.
- **C L1:** Only agent tools whose metadata carries approval_actions are gated; direct component execution and the Assistant's code-running path never cross the gate. — [src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py:59-66](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py#L59-L66); [src/backend/base/langflow/agentic/services/assistant_service.py:1596-1599](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/agentic/services/assistant_service.py#L1596-L1599) (verified)
  - *To reach the next level:* Unflagged tools and non-agent paths bypass; L2 needs all built-in tools gated.
- **D L0:** approval_actions is empty unless the flow author selects actions per tool, so approval is opt-in. — [src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py:59-66](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py#L59-L66) (verified)
  - *To reach the next level:* Approval is opt-in; L1 needs approval on by default for consequential tools.
- **B L1:** Assistant canvas edits get a flow-version restore point; API requests, messages and code execution are irreversible. — [src/backend/base/langflow/agentic/services/restore_point.py:1-6](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/agentic/services/restore_point.py#L1-L6) (verified)
  - *To reach the next level:* External actions (HTTP writes, messages, code) have no undo; L2 needs reversibility for the common case.
- **Cap:** C2-POWERBYPASS — The Assistant's runtime validation executes model-generated component code in-process without any approval gate, on by default.

### C3 Tool & action scoping — 0.45 (high)

The built-in network and file components are well validated. URL, API Request and Web Search block internal and cloud-metadata addresses, pin DNS, and re-validate each redirect. File components resolve paths and keep them inside the user's storage directory. Both protections are on by default. But the toolbox also has general-purpose tools, such as the Python Interpreter, raw HTTP to any public host, custom component code and whole MCP servers, and there is no central policy layer that every tool inherits.

- **S L2:** Strong allowlist-style checks exist (SSRF IP blocking with DNS pinning and per-hop redirect validation; resolved-path containment), but general tools such as the Python Interpreter and arbitrary-method HTTP stay largely passthrough. — [src/lfx/src/lfx/components/data_source/api_request.py:546](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/data_source/api_request.py#L546); [src/lfx/src/lfx/components/data_source/api_request.py:577-578](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/data_source/api_request.py#L577-L578); [src/lfx/src/lfx/utils/file_path_security.py:294-299](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/utils/file_path_security.py#L294-L299); [src/lfx/src/lfx/components/utilities/python_repl_core.py:38-41](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/utilities/python_repl_core.py#L38-L41) (verified)
  - *To reach the next level:* General-purpose tools (code, any public URL/method) remain the default building blocks; L3 needs allowlist validation on every tool's arguments.
- **C L2:** SSRF and path checks are applied per built-in component; MCP tools and custom components get no shared validation layer. — [src/lfx/src/lfx/components/data_source/url.py:287](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/data_source/url.py#L287); [src/lfx/src/lfx/services/settings/groups/security.py:259](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L259) (verified)
  - *To reach the next level:* No shared validation layer for MCP and custom components; L3 needs extension tools wrapped by a shared layer.
- **D L2:** The Agent has no tools until a flow author wires them, but the on-by-default Assistant ships with build/run/generate tools, and an MCP Tools node exposes a server's whole tool set. — [src/lfx/src/lfx/services/settings/groups/variables.py:20](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/variables.py#L20); [src/lfx/src/lfx/services/settings/groups/security.py:23](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L23) (verified)
  - *To reach the next level:* Write/exec tools are routinely wired, with no read-only default set; L3 needs a read-only default with explicit enabling of write/exec.
- **B L1:** A misused tool reaches any public host and in-process code execution; only internal addresses and out-of-storage file paths are blocked. — [src/lfx/src/lfx/components/data_source/api_request.py:546](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/data_source/api_request.py#L546); [src/lfx/src/lfx/services/settings/groups/security.py:117](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L117) (verified)
  - *To reach the next level:* Reach is server-wide with only minor limits; L2 needs tools scoped to a project/workspace.
- **Cap:** none

### C4 Code-execution isolation — 0.50 (high)

By default, model-written Python (the Python Interpreter tool, Smart Transform) runs inside the Langflow server process. The only protection is restricted builtins and AST checks, which the maintainers describe as best-effort and not a guaranteed sandbox. Custom component code, and the Assistant's validation of model-generated components, also run in-process, and MCP stdio servers start on the host. An escape lands in the process that holds the database, the secret key and every stored credential. An optional QEMU microVM backend (exec-sandbox) with no network and fail-closed behaviour exists, but it is off by default and covers only the Python Interpreter and REPL components.

- **default configuration** (default; raw 0.25 → 0.25)
  - **S L1:** In-process exec with curated builtins, an AST gadget check and module proxies; the code itself says this is NOT a guaranteed sandbox. — [src/lfx/src/lfx/components/utilities/python_repl_core.py:126-130](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/utilities/python_repl_core.py#L126-L130); [src/lfx/src/lfx/utils/python_repl_security.py:39-40](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/utils/python_repl_security.py#L39-L40); [src/lfx/src/lfx/services/settings/groups/security.py:196-202](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L196-L202) (verified)
    - *To reach the next level:* Filtering inside a full Python runtime; L2 needs OS-level separation.
  - **C L1:** The filter covers the Python Interpreter/REPL and Smart Transform, but custom component classes are exec'd unfiltered, assistant-generated code runs in-process behind only an AST denylist, and MCP stdio servers run on the host. — [src/lfx/src/lfx/custom/validate.py:692](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/custom/validate.py#L692); [src/backend/base/langflow/agentic/helpers/validation.py:280-308](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/agentic/helpers/validation.py#L280-L308); [src/lfx/src/lfx/base/mcp/util.py:2033](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/mcp/util.py#L2033) (verified)
    - *To reach the next level:* Other execution paths (custom components, Assistant validation, MCP stdio) bypass it; L2 needs most paths covered.
  - **D L2:** The filter is always on for the interpreter components, but allow_custom_components defaults to True, which leaves the unfiltered custom-code path open without warning. — [src/lfx/src/lfx/services/settings/groups/security.py:117](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L117); [src/lfx/src/lfx/services/settings/groups/security.py:183](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L183) (verified)
    - *To reach the next level:* Unfiltered paths are enabled by a default config value; L3 needs disabling to require an explicit, loudly named operator flag.
  - **B L0:** An escape runs inside the server process, with the DB, the secret key, environment and full network. — [src/lfx/src/lfx/utils/python_repl_security.py:39-41](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/utils/python_repl_security.py#L39-L41); [src/lfx/src/lfx/services/settings/utils.py:113-116](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/utils.py#L113-L116) (verified)
    - *To reach the next level:* Escape reaches host-equivalent server authority and secrets; L1 needs at least the secrets kept out of reach.
- **opt-in exec-sandbox QEMU microVM backend (LANGFLOW_SANDBOX_BACKEND=exec-sandbox)** (alt; raw 0.53, cap G1 → 0.50) ← counted
  - **S L4:** Each execution runs in a dedicated QEMU microVM with a read-only rootfs and no host filesystem; software emulation is refused by default. — [src/lfx/src/lfx/services/settings/groups/security.py:203-213](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L203-L213); [src/lfx/src/lfx/components/utilities/python_repl_core.py:118-119](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/utilities/python_repl_core.py#L118-L119) (verified)
  - **C L1:** Only the Python Interpreter and legacy REPL route to the sandbox; custom components, Smart Transform, Assistant validation and MCP stdio stay in-process or on the host. — [src/lfx/src/lfx/services/settings/groups/security.py:197-198](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L197-L198) (verified)
    - *To reach the next level:* Other execution paths stay on the host; L2 needs most paths sandboxed.
  - **D L0:** sandbox_backend defaults to 'none'. — [src/lfx/src/lfx/services/settings/groups/security.py:196-202](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L196-L202) (verified)
    - *To reach the next level:* Off by default; L1 needs the sandbox on by default.
  - **B L3:** No network by default, memory and timeout limits, no host filesystem, and fail-closed when unavailable. — [src/lfx/src/lfx/services/settings/groups/security.py:217-225](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L217-L225); [src/lfx/src/lfx/services/settings/groups/security.py:212-213](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/security.py#L212-L213) (verified)
    - *To reach the next level:* Per-call ephemerality is not verified in Langflow's code (upstream warm pool); L4 needs ephemeral, verified per-run VMs.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

### C5 Untrusted input blast radius — 0.00 (high)

Nothing structural limits what a hijacked agent can do. Web pages, files, search results and MCP tool output come back as ordinary tool messages. The only defence is a line in the default system prompt telling the model to treat tool output as untrusted. One agent can read attacker-controlled content, hold stored credentials, and send data to any public host or take irreversible actions, all without a human.

- **S L0:** The only injection defence is a system-prompt instruction; there is no taint tracking or quarantine. — [src/lfx/src/lfx/base/agents/default_system_prompt.py:23](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/agents/default_system_prompt.py#L23); searched `rg -n -i 'taint|quarantin|untrusted'` in `src/lfx/src/lfx/components/models_and_agents src/lfx/src/lfx/base/agents` → 4 hits (2 hits are system-prompt text, 2 are A2A card coercion; none gate tools on provenance.) (verified)
  - *To reach the next level:* Prompt-only; L1 needs at least a detection layer on by default.
- **C L0:** Tool results, MCP output and fetched pages enter context with the same standing as user input. — [src/lfx/src/lfx/components/data_source/url.py:287](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/data_source/url.py#L287); [src/lfx/src/lfx/base/agents/default_system_prompt.py:23](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/agents/default_system_prompt.py#L23) (verified)
  - *To reach the next level:* Untrusted sources are not distinguished; L1 needs at least one source handled.
- **D L0:** No structural control exists to enable. — [src/lfx/src/lfx/base/agents/default_system_prompt.py:23](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/agents/default_system_prompt.py#L23) (verified)
  - *To reach the next level:* No control on by default; L1 needs one.
- **B L0:** A hijacked agent can exfiltrate via API Request/URL to any public host and take irreversible actions with stored credentials, unattended. — [src/lfx/src/lfx/components/data_source/api_request.py:546](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/data_source/api_request.py#L546); [src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py:59-66](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent_helpers/tool_approval.py#L59-L66) (verified)
  - *To reach the next level:* Leak plus irreversible action happens without a human; L1 needs at least one of them gated.
- **Cap:** C5-WORSTCASE — Worst case (B L0): a hijacked agent can leak data and take irreversible actions unattended.

### C6 Memory, context & configuration integrity — 0.30 (high)

Agent chat history is stored per session and fed back as conversation (up to 100 messages by default) with no validation, so injected text persists for as long as a session id is reused. Queries scope history by session, flow and user. The Assistant also saves model-generated component code to disk after scanning it, and later turns import and execute that code. Vector stores and knowledge bases written by flows have no provenance tagging.

- **S L1:** Chat history writes are not validated and are re-injected as conversation; only the Assistant's generated-component store has a (denylist) scan. — [src/lfx/src/lfx/components/models_and_agents/agent.py:1003-1013](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent.py#L1003-L1013); [src/lfx/src/lfx/components/models_and_agents/agent.py:217-220](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent.py#L217-L220) (verified)
  - *To reach the next level:* No provenance labelling or validation of persisted memory; L2 needs memory presented as data with provenance.
- **C L1:** The generated-component registry is scanned; chat history, vector stores and knowledge bases are not controlled. — [src/backend/base/langflow/agentic/services/user_components.py:3-9](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/agentic/services/user_components.py#L3-L9) (verified)
  - *To reach the next level:* Most stores uncontrolled; L2 needs the main memory store controlled.
- **D L2:** History retrieval filters on session_id, flow_id and user_id in the query. — [src/lfx/src/lfx/components/models_and_agents/agent.py:1008-1013](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent.py#L1008-L1013) (verified)
  - *To reach the next level:* In the default configuration generated components go to a shared directory, and the model can write to any session id it is given; L3 needs the model unable to cross namespaces.
- **B L1:** Poisoned history persists across reuse of a session, and persisted generated components are later imported and executed, which can trigger tool use. — [src/backend/base/langflow/agentic/services/user_components.py:3-9](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/agentic/services/user_components.py#L3-L9) (verified)
  - *To reach the next level:* Persistence can trigger tool use and code execution; L2 needs persistence to influence only text or gated actions.
- **Cap:** none
- **Notes:** The `langflow` entry point calls load_dotenv() at import (src/backend/base/langflow/langflow_launcher.py:6-8). Langflow is a server, not an agent working inside a cloned repository, so this was treated as operator scope and C6-REPOCONFIG was not applied.

### C7 Third-party extensions — 0.10 (high)

On startup, Langflow adds an MCP server entry for each user's starter project. The entry runs `uvx mcp-proxy` with no version pin, so whatever release PyPI serves is downloaded and run when the server is checked or used. Users can add more stdio servers through npx/uvx/docker. A command allowlist, a shell-metacharacter policy and an environment-variable denylist apply, but versions are not pinned and nothing checks integrity. The package allowlist and the interpreter and Docker hardening are opt-in. Stdio servers start with a scrubbed environment (PATH plus their own config), but they run as the same OS user.

- **S L0:** Auto-configured `uvx mcp-proxy` resolves the latest PyPI release; user-added npx/uvx servers are unpinned with no hash check. — [src/backend/base/langflow/api/utils/mcp/config_utils.py:510-515](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/api/utils/mcp/config_utils.py#L510-L515); [src/backend/base/langflow/api/v1/projects_mcp_helpers.py:132-135](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/api/v1/projects_mcp_helpers.py#L132-L135); [src/lfx/src/lfx/services/settings/groups/mcp.py:132-139](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/mcp.py#L132-L139); searched `rg -n -i 'sha256|integrity|hash'` in `src/lfx/src/lfx/base/mcp/security.py` → 1 hits (The single hit is the PYTHONHASHSEED env-var name in a denylist, not an integrity check.) (verified)
  - *To reach the next level:* Third-party packages run unpinned and unverified; L1 needs user-chosen sources only, with nothing auto-installed.
- **C L0:** No extension type has version or integrity verification by default. — [src/lfx/src/lfx/base/mcp/security.py:49-61](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/mcp/security.py#L49-L61) (verified)
  - *To reach the next level:* No extension type is verified; L1 needs at least one.
- **D L0:** Startup reconciliation auto-adds the mcp-proxy server entry for every user's starter project without consent. — [src/backend/base/langflow/api/v1/mcp_projects.py:1736](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/api/v1/mcp_projects.py#L1736); [src/lfx/src/lfx/services/settings/groups/mcp.py:85-91](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/mcp.py#L85-L91) (verified)
  - *To reach the next level:* Extensions are enabled automatically; L1 needs install on first use behind consent.
- **B L2:** Stdio servers get a scrubbed env (DEBUG, PATH and validated config vars) but run as the same OS user, with filesystem access to the config dir. — [src/lfx/src/lfx/base/mcp/util.py:2019-2027](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/mcp/util.py#L2019-L2027) (verified)
  - *To reach the next level:* No per-extension sandbox or scoped credentials; L3 needs per-extension sandboxing.
- **Cap:** C7-RCELOAD — By default Langflow configures, and launches when the server is listed or used, an unpinned `uvx mcp-proxy` from PyPI, executing remote code without user consent.

### C8 Secrets & sensitive-data protection — 0.40 (high)

Credential-type variables are Fernet-encrypted in the database. The key sits in a permission-restricted file in the same config directory, so anyone who can read that directory can decrypt them. Settings use SecretStr. Transaction logs mask values under sensitive key names, and telemetry sends only allowlisted input fields. Usage telemetry to Scarf is on by default and includes error messages. Nothing redacts secrets before model-bound messages. Provider keys are long-lived, and in-process code can reach them.

- **S L2:** Fernet encryption at rest for credential variables with a co-located key file, SecretStr settings, and key-name masking in transactions. — [src/backend/base/langflow/services/variable/service.py:660-661](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/variable/service.py#L660-L661); [src/lfx/src/lfx/services/settings/utils.py:113-116](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/utils.py#L113-L116); [src/backend/base/langflow/services/database/models/transactions/model.py:127-132](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/database/models/transactions/model.py#L127-L132) (verified)
  - *To reach the next level:* No OS keychain or secret manager, and no redaction before model-bound messages; L3 needs both.
- **C L2:** Transaction logs and stored vertex data are masked by key name, and MCP subprocess env is scrubbed, but model-bound messages and telemetry error strings are not redacted. — [src/backend/base/langflow/services/database/models/transactions/model.py:11-14](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/database/models/transactions/model.py#L11-L14); [src/backend/base/langflow/services/telemetry/schema.py:18](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/telemetry/schema.py#L18) (verified)
  - *To reach the next level:* Model-bound messages and telemetry not covered; L3 needs all listed paths.
- **D L1:** Telemetry is on unless DO_NOT_TRACK is set; payloads are mostly content-free (allowlisted input fields) but include error messages. — [src/lfx/src/lfx/services/settings/groups/telemetry.py:15](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/telemetry.py#L15); [src/lfx/src/lfx/inputs/inputs.py:502](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/inputs/inputs.py#L502) (verified)
  - *To reach the next level:* Telemetry is on by default; L2 needs it opt-in.
- **B L1:** Stored provider and API keys are long-lived and moderately scoped; the auto-configured MCP proxy also receives a Langflow API key as an argv value. — [src/backend/base/langflow/api/utils/mcp/config_utils.py:503-520](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/api/utils/mcp/config_utils.py#L503-L520) (verified)
  - *To reach the next level:* Long-lived keys; L2 needs scoped keys.
- **Cap:** none

### C9 Audit & traceability — 0.45 (high)

Every component run is written to a transactions table with inputs, outputs, status and timestamp. Agent tool calls are kept in stored messages as tool-use content blocks with name, input and output. Records lack an actor or approver field, and the authorization audit log is off by default. Writes go through a best-effort background writer that drops rows on a hard crash. Retention keeps only the newest 3,000 transactions, and the server process, where flows and code run, can alter the records.

- **S L2:** Structured per-component transaction rows and per-tool-call content blocks (name, input, output, error). — [src/backend/base/langflow/services/database/models/transactions/model.py:113-121](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/database/models/transactions/model.py#L113-L121); [src/lfx/src/lfx/schema/content_types.py:171-175](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/schema/content_types.py#L171-L175) (verified)
  - *To reach the next level:* No actor, approver or delegation attribution on records; L3 needs principal/approver fields and correlation IDs.
- **C L2:** Every component execution and agent tool call (including MCP tools wired to the agent) is recorded, but approvals and denials are not in the same record, and authz audit is opt-in. — [src/lfx/src/lfx/base/agents/events.py:232](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/base/agents/events.py#L232); [src/lfx/src/lfx/services/settings/auth.py:301-302](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/auth.py#L301-L302) (verified)
  - *To reach the next level:* Approvals and denials not consistently captured; L3 needs them recorded.
- **D L2:** On by default in the server DB outside any workspace, but writable by the same process that runs flows and code; retention prunes old rows. — [src/lfx/src/lfx/services/settings/groups/telemetry.py:19](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/telemetry.py#L19); [src/lfx/src/lfx/services/settings/groups/observability.py:12](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/observability.py#L12) (verified)
  - *To reach the next level:* The executing process can alter or delete records; L3 needs a writer the model cannot control.
- **B L1:** Best-effort batched background writer; hard kills lose buffered rows and the queue drops the oldest rows under pressure. — [src/backend/base/langflow/services/telemetry_writer/service.py:18-19](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/services/telemetry_writer/service.py#L18-L19) (verified)
  - *To reach the next level:* Records are flushed late and can be lost; L2 needs per-action flush with surfaced errors.
- **Cap:** none

### C10 Limits & kill switch — 0.45 (high)

The Agent is capped at 15 model calls by default, enforced by middleware. MCP tool calls time out after 180 seconds, and synchronous v2 workflow runs after 300. There is no token or cost budget. Background jobs have no timeout by default. Sub-flows and agents used as tools start with their own fresh limits. Cancelling a build cancels the asyncio task, but in-process code already running is not interrupted.

- **S L2:** Iteration cap via ModelCallLimitMiddleware plus MCP tool and sync-workflow wall-clock timeouts. — [src/lfx/src/lfx/components/models_and_agents/agent.py:643-644](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent.py#L643-L644); [src/lfx/src/lfx/services/settings/groups/mcp.py:33](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/mcp.py#L33); [src/lfx/src/lfx/services/settings/groups/runtime.py:147](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/runtime.py#L147); searched `rg -n -i 'max_tokens_total|cost_limit|budget'` in `src/lfx/src/lfx/components/models_and_agents/agent.py src/lfx/src/lfx/base/agents/agent.py` → 0 hits (No token or cost budget in the agent loop.) (verified)
  - *To reach the next level:* No token/cost cap or rate limits on side-effecting tools; L3 needs both.
- **C L2:** Top-level agent loop plus tool timeouts; sub-flows and background jobs run with their own budgets. — [src/lfx/src/lfx/services/settings/groups/runtime.py:109-112](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/runtime.py#L109-L112) (verified)
  - *To reach the next level:* Sub-agents and background jobs do not share the parent budget; L3 needs them counted against it.
- **D L2:** Sensible default of 15 iterations, operator/flow-author configurable up to 128000. — [src/lfx/src/lfx/components/models_and_agents/agent.py:101-106](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/components/models_and_agents/agent.py#L101-L106) (verified)
  - *To reach the next level:* Delegating to a sub-flow or agent-as-tool resets the budget; L3 needs limits that delegation cannot reset.
- **B L1:** Background jobs are unbounded by default, and a cancel stops the task loop but cannot interrupt in-process exec already running. — [src/lfx/src/lfx/services/settings/groups/runtime.py:109](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/lfx/src/lfx/services/settings/groups/runtime.py#L109); [src/backend/base/langflow/api/v1/chat.py:533-548](https://github.com/langflow-ai/langflow/blob/f9b283243d2fdd8502cb4ffd606c3058cff5017e/src/backend/base/langflow/api/v1/chat.py#L533-L548) (verified)
  - *To reach the next level:* Unbounded background work and non-interruptible execution; L2 needs moderate ceilings for every run.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: URL / Web Search / File / MCP tool output enters agent context (src/lfx/src/lfx/components/data_source/url.py:287) · [B] sensitive data/systems: Encrypted credential variables decrypted into components in the same process (src/backend/base/langflow/services/variable/service.py:661) · [C] state change / egress: API Request to any public host and code execution tools (src/lfx/src/lfx/components/data_source/api_request.py:546) · Same default session? Yes

## Highest-impact improvements
1. Harden default authentication for `langflow run`. — C1 D L0→L2, +0.100 before caps (Playbook 4)
2. Pin mcp-proxy to an exact version (as mcp-composer already is) and require consent before auto-adding MCP servers. — C7 D L0→L2, +0.100 before caps (Playbook 3)
3. Pre-select approval actions for code-execution and non-GET HTTP tools so the agent pauses for a human by default. — C2 D L0→L2, +0.100 before caps (Playbook 5)
4. Route every code-execution path (custom components, Smart Transform, Assistant validation) through the exec-sandbox backend when configured. — C4 C L1→L3, +0.150 before caps (Playbook 3)
5. Set a default background_job_timeout and make sub-flows/agents-as-tools share the parent's iteration budget. — C10 B L1→L2, +0.050 before caps (Playbook 3 step 3)

## Re-audit log
- No changes.

## Limitations
- Static source review of the pinned commit only; nothing was executed, installed, or probed.
- No release tag points at the pinned commit; pyproject.toml declares version 1.12.4.
- Scored the README-led local install (`langflow run`). The official Docker image differs in its authentication and user defaults (docker/build_and_push.Dockerfile:231-237), which would improve C1.
- LangChain HumanInTheLoopMiddleware behaviour (which arguments the approval description contains) and exec-sandbox upstream VM lifecycle were inferred from library contracts, not read in their source.
- Not examined in depth: the frontend's markdown rendering as an exfiltration channel, the src/bundles provider packages, enterprise authorization plugins, Langflow Desktop, and the A2A/public-flow serving plane (opt-in features).
- No text aimed at AI reviewers was found in AGENTS.md, CLAUDE.md or other markdown files.
