|
122 | 122 | } |
123 | 123 | ) |
124 | 124 |
|
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. |
142 | 131 |
|
143 | 132 | # -- Default (lenient / previous behavior) -- |
144 | 133 | DOCKER_DANGEROUS_ARGS = frozenset({"--privileged", "--cap-add"}) |
@@ -303,17 +292,13 @@ def validate_mcp_stdio_config( |
303 | 292 | wraps a non-allowed command, an env var is in the blocklist, or a docker arg |
304 | 293 | breaks container isolation. |
305 | 294 | """ |
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"). |
317 | 302 | args = list(args or []) |
318 | 303 | if command and not _is_file_path(command): |
319 | 304 | try: |
|
0 commit comments