fix(security): refuse MCP stdio server configuration on the public flow path (#14644)
* fix(security): refuse MCP stdio server configuration on the public flow path The public-flow guards only reason about the node `code` field: `validate_public_flow_no_code_execution` matches component types and code hashes, and `prepare_public_flow_build` substitutes the server's trusted source into every code-bearing node. An MCP Tools node's stdio server configuration — the executable and its arguments — lives in the `mcp_server` input's VALUE instead, so neither guard inspected or rewrote it. A public flow carrying one therefore let an unauthenticated visitor cause the server to spawn that process under the Langflow service account, which is the exact outcome the public-flow guards exist to prevent. `validate_public_flow_no_code_execution` now rejects a public build whose graph selects the MCP stdio transport, mirroring `update_tools`' own transport selection (explicit `mode` of `Stdio`, otherwise the presence of `command`) so a configuration this check passes cannot become a spawn at the sink. Detection follows the stored configuration's shape rather than the node type, because the same component is legitimate over HTTP/SSE: remote MCP transports spawn nothing and keep working on public flows. The stdio-only legacy `MCPStdio` component is blocked by type. The scan walks every template field and recurses into inlined sub-flows, matching the existing blocklist collector. Placing the check in the shared validator covers all four unauthenticated execute paths (v1 build_public_tmp, v2 workflows/public, and both A2A entry points), both at their route-level precheck and at the post-substitution recheck inside `prepare_public_flow_build`, including under the `allow_public_custom_components` opt-in. Authenticated builds are unaffected. Regression tests cover the guard functions directly (stdio via `command`, via explicit `mode`, bare and `mcpServers`-map shapes, a relabelled field key, nested sub-flows, the legacy component type, and the opt-in path), assert that HTTP/SSE configurations still build, assert no false positive on an ordinary dict input carrying a `command` key, and exercise both reported endpoints end to end. Fixes LE-2244 * test(security): exercise the genuinely unauthenticated public path The shared test client persists access-token cookies from logged_in_headers, so setting client_id alone left the request authenticated and the test did not cover the unauthenticated boundary it claims. Clear cookies first, matching the _send_unauthenticated helper in tests/unit/api/v2/test_workflow_public.py. The guard still rejects the build, so this strengthens the assertion without changing the outcome.
E
Eric Hare committed
d6967f6657668b40c5641bebf3a1299758fd7f91
Parent: d4c8ea1
Committed by GitHub <noreply@github.com>
on 8/19/2026, 5:26:03 PM