Skip to content

Commit 7c39928

Browse files
jordanrfraziererichare
authored andcommitted
docs(security): tighten over-explained comments in the MCP/env-var guards
- Collapse the triplicated docker-policy prose in mcp/security.py to a pointer to the mcp_server_docker_hardening setting docstring + the per-set inline comments. - Fix the env_var_security reserved-names summary to list all covered categories (token-signing / OAuth / mail-relay were added but not reflected). - Trim the line-by-line narration on the stdio command-tokenization step.
1 parent fffe582 commit 7c39928

2 files changed

Lines changed: 15 additions & 30 deletions

File tree

src/lfx/src/lfx/base/mcp/security.py

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -122,23 +122,12 @@
122122
}
123123
)
124124

125-
# SECURITY: Docker-flag policy for MCP stdio servers. ``docker`` is allowlisted (a legitimate MCP
126-
# transport), but several flags turn a container run into host access (``-v /:/host`` mounts the
127-
# whole host filesystem, ``-v /var/run/docker.sock:/s`` grants Docker-API root, ``--device``
128-
# exposes host devices, ``--network host`` shares the host network, ...). There are TWO modes,
129-
# selected by ``LANGFLOW_MCP_SERVER_DOCKER_HARDENING`` (default off):
130-
#
131-
# * Default (off) -- the lenient baseline that preserves existing single-tenant behavior, where
132-
# docker MCP servers legitimately use volume mounts, custom networks, etc. Only ``--privileged``
133-
# / ``--cap-add`` and the host-namespace ``=`` forms are rejected.
134-
# * Hardened (on) -- the comprehensive policy below for multi-tenant / untrusted-tenant
135-
# deployments: host filesystem/device mounts and privilege flags are rejected outright, the
136-
# namespace flags are rejected only for the genuinely dangerous host / another-container
137-
# values, the network is restricted to the default-isolated values, and ``--security-opt`` is
138-
# rejected only when it downgrades the sandbox (``no-new-privileges`` stays allowed).
139-
#
140-
# Both modes handle the inline (``--volume=/:/host``) and space-separated (``--volume /:/host``)
141-
# forms.
125+
# SECURITY: docker-flag policy for MCP stdio servers. ``docker`` is allowlisted but several flags
126+
# turn a container run into host access. Two modes, selected by LANGFLOW_MCP_SERVER_DOCKER_HARDENING
127+
# (default off = lenient/previous behavior, on = strict multi-tenant policy) -- the
128+
# mcp_server_docker_hardening setting docstring has the operator-facing description; the per-set
129+
# comments below cover what each blocks. Both modes handle the inline (``--volume=/:/host``) and
130+
# space-separated (``--volume /:/host``) forms.
142131

143132
# -- Default (lenient / previous behavior) --
144133
DOCKER_DANGEROUS_ARGS = frozenset({"--privileged", "--cap-add"})
@@ -303,17 +292,13 @@ def validate_mcp_stdio_config(
303292
wraps a non-allowed command, an env var is in the blocklist, or a docker arg
304293
breaks container isolation.
305294
"""
306-
# 0) Tokenize a command that carries its own arguments (e.g. "bash -c '<payload>'").
307-
# Without this, a tenant can pack the whole payload into ``command`` with empty ``args``:
308-
# extract_base_command() only inspects the first token for the allowlist, the metacharacter
309-
# scan only iterates ``args``, and the shell-wrapper check is skipped when ``args`` is empty
310-
# -- so the embedded ``-c '<payload>'`` would never be examined. Splitting here folds those
311-
# embedded tokens into ``args`` so every check below sees them. Applies to ALL callers
312-
# (update_tools, the REST MCPServerConfig, the legacy stdio component), keeping the
313-
# REST-layer and execution-time enforcement identical.
314-
# Do NOT split file-path commands: an absolute/relative/Windows path may legitimately
315-
# contain spaces (e.g. "C:\\Program Files\\nodejs\\node.exe") and carries no embedded
316-
# shell arguments -- extract_base_command resolves those directly.
295+
# 0) Tokenize a command that carries its own arguments (e.g. "bash -c '<payload>'"). A tenant
296+
# could otherwise pack the whole payload into ``command`` with empty ``args`` and slip past
297+
# the checks below, which key off the first token / only scan ``args``. Folding the embedded
298+
# tokens into ``args`` makes every check see them -- at all callers (update_tools, the REST
299+
# MCPServerConfig, the legacy stdio component), so REST and execution enforcement stay equal.
300+
# Don't split file-path commands: a Windows/absolute path may contain spaces but carries no
301+
# embedded shell args (e.g. "C:\\Program Files\\nodejs\\node.exe").
317302
args = list(args or [])
318303
if command and not _is_file_path(command):
319304
try:

src/lfx/src/lfx/utils/env_var_security.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333

3434
# Exact names that carry infrastructure secrets but do not use a reserved prefix. These are
3535
# never legitimate flow values (unlike LLM provider API keys, which intentionally remain
36-
# resolvable). Covers the database, cloud-IAM, cache, and VCS credentials an operator is most
37-
# likely to have in the process environment of a multi-tenant deployment.
36+
# resolvable). Covers the database, cache, cloud-IAM, token-signing, OAuth/SSO, mail-relay, and
37+
# VCS credentials an operator is most likely to have in a multi-tenant deployment's environment.
3838
_RESERVED_ENV_NAMES: frozenset[str] = frozenset(
3939
{
4040
# Application / database

0 commit comments

Comments
 (0)