Summary
Clouds Coder automatically treats a workspace-controlled LLM.config.json as its MCP configuration. Any enabled stdio declaration can select a local executable, arguments, environment, and working directory. The manager launches the declaration during ordinary service startup and also launches new or changed declarations during its mtime-based hot reload. There is no workspace trust decision, per-command approval, effective-command fingerprint, revision/config digest binding, or content-change confirmation before subprocess.Popen.
This report is about a configured workspace whose later repository content is lower-trust than the application operator. It is not a claim that merely cloning or browsing an arbitrary repository executes code. Running an untrusted source checkout is separately an explicit execution of that checkout's Python program.
Affected versions
- Latest checked GitHub
main: a8c510b0b7dcfae73d188040dc4b80e2f45574e5 (a8c510b, 2026-07-24).
- Latest checked PyPI release:
clouds-coder 2026.7.23.
- The affected source paths are
Clouds_Coder.py:115-153, 85010-85112, 14900-15016, 15068-15080, 15552-15689, and 94350-94357.
Preconditions and impact
The operator must have configured the application to use the target workspace, for example by setting AGENT_WORKDIR or through a deployment wrapper that supplies the equivalent workspace root. After that authorization, a later commit or other content change to LLM.config.json can select a new local process. The process runs with the service account's permissions and inherited environment; no model request, session, prompt, or MCP tool call is required.
Reproduction
- Use a trusted copy or installed version of
Clouds_Coder.py. Create a separate workspace and make it the current directory.
- Create
LLM.config.json in that workspace with this content:
{
"provider": "ollama",
"ollama_url": "http://127.0.0.1:9",
"ollama_model": "",
"mcpServers": {
"marker": {
"command": "/usr/bin/python3",
"args": [
"-c",
"from pathlib import Path; Path('clouds-coder-poc-marker').write_text('executed\\n')"
]
}
}
}
- Start the trusted runtime with the workspace selected and no model interaction:
AGENT_WORKDIR="$PWD" python3 /path/to/trusted/Clouds_Coder.py \
--host 127.0.0.1 --port 18080 \
--no_Skills_UI --no_rag_admin --no_code_admin --no_ide --no_download_js_lib
- Before creating a session or sending a prompt, check whether
clouds-coder-poc-marker exists in the workspace.
Expected result: the marker exists. The service may log an MCP handshake failure because the marker command exits immediately; that message occurs after the child process has already been spawned. With an otherwise identical workspace configuration that has no MCP block, the marker is not created.
- For the content-change path, first start with a configuration containing only the provider fields, then add the
mcpServers object while the service remains running. Wait for the monitor interval.
Expected result: the service logs a hot-swap for marker and creates the marker without a trust or command-content confirmation.
Why this happens
Clouds_Coder.py:115-153 resolves the effective workspace and LLM.config.json. AppContext reads that file at Clouds_Coder.py:85010 and constructs the MCP manager at Clouds_Coder.py:85112. mcp_extract_server_configs and mcp_normalize_server_configs at Clouds_Coder.py:14900-15016 accept mcpServers, mcp_servers, and mcp, default entries to enabled, and preserve executable fields. Startup calls start_async at Clouds_Coder.py:94350-94357; the stdio path reaches subprocess.Popen at Clouds_Coder.py:15068-15080. The hot-reload watcher at Clouds_Coder.py:15672-15689 checks only mtime and calls reload_from_config, which starts changed records without an approval or content binding.
Security impact
The missing control allows a lower-trust workspace revision to acquire the local process-execution capability of a previously configured service. The accurate trigger is service startup or a configuration mtime change in an already selected workspace, not repository browsing. The issue is deterministic configuration execution and does not depend on prompt injection or model behavior.
Suggested fix
Keep executable MCP declarations in user-private configuration, or disable workspace MCP by default. If workspace MCP is supported, require a first-use decision that displays the resolved command, args, cwd, environment keys, transport, workspace identity, and configuration revision/digest. Bind the receipt to the specific declaration and referenced executable/script identities, re-prompt when any command-bearing content changes, and repeat the validation immediately before every spawn, hot reload, and crash restart. Do not treat selecting the workspace as blanket approval for all future command-bearing revisions.
Summary
Clouds Coder automatically treats a workspace-controlled
LLM.config.jsonas its MCP configuration. Any enabled stdio declaration can select a local executable, arguments, environment, and working directory. The manager launches the declaration during ordinary service startup and also launches new or changed declarations during its mtime-based hot reload. There is no workspace trust decision, per-command approval, effective-command fingerprint, revision/config digest binding, or content-change confirmation beforesubprocess.Popen.This report is about a configured workspace whose later repository content is lower-trust than the application operator. It is not a claim that merely cloning or browsing an arbitrary repository executes code. Running an untrusted source checkout is separately an explicit execution of that checkout's Python program.
Affected versions
main:a8c510b0b7dcfae73d188040dc4b80e2f45574e5(a8c510b, 2026-07-24).clouds-coder 2026.7.23.Clouds_Coder.py:115-153,85010-85112,14900-15016,15068-15080,15552-15689, and94350-94357.Preconditions and impact
The operator must have configured the application to use the target workspace, for example by setting
AGENT_WORKDIRor through a deployment wrapper that supplies the equivalent workspace root. After that authorization, a later commit or other content change toLLM.config.jsoncan select a new local process. The process runs with the service account's permissions and inherited environment; no model request, session, prompt, or MCP tool call is required.Reproduction
Clouds_Coder.py. Create a separate workspace and make it the current directory.LLM.config.jsonin that workspace with this content:{ "provider": "ollama", "ollama_url": "http://127.0.0.1:9", "ollama_model": "", "mcpServers": { "marker": { "command": "/usr/bin/python3", "args": [ "-c", "from pathlib import Path; Path('clouds-coder-poc-marker').write_text('executed\\n')" ] } } }AGENT_WORKDIR="$PWD" python3 /path/to/trusted/Clouds_Coder.py \ --host 127.0.0.1 --port 18080 \ --no_Skills_UI --no_rag_admin --no_code_admin --no_ide --no_download_js_libclouds-coder-poc-markerexists in the workspace.Expected result: the marker exists. The service may log an MCP handshake failure because the marker command exits immediately; that message occurs after the child process has already been spawned. With an otherwise identical workspace configuration that has no MCP block, the marker is not created.
mcpServersobject while the service remains running. Wait for the monitor interval.Expected result: the service logs a hot-swap for
markerand creates the marker without a trust or command-content confirmation.Why this happens
Clouds_Coder.py:115-153resolves the effective workspace andLLM.config.json.AppContextreads that file atClouds_Coder.py:85010and constructs the MCP manager atClouds_Coder.py:85112.mcp_extract_server_configsandmcp_normalize_server_configsatClouds_Coder.py:14900-15016acceptmcpServers,mcp_servers, andmcp, default entries to enabled, and preserve executable fields. Startup callsstart_asyncatClouds_Coder.py:94350-94357; the stdio path reachessubprocess.PopenatClouds_Coder.py:15068-15080. The hot-reload watcher atClouds_Coder.py:15672-15689checks only mtime and callsreload_from_config, which starts changed records without an approval or content binding.Security impact
The missing control allows a lower-trust workspace revision to acquire the local process-execution capability of a previously configured service. The accurate trigger is service startup or a configuration mtime change in an already selected workspace, not repository browsing. The issue is deterministic configuration execution and does not depend on prompt injection or model behavior.
Suggested fix
Keep executable MCP declarations in user-private configuration, or disable workspace MCP by default. If workspace MCP is supported, require a first-use decision that displays the resolved command, args, cwd, environment keys, transport, workspace identity, and configuration revision/digest. Bind the receipt to the specific declaration and referenced executable/script identities, re-prompt when any command-bearing content changes, and repeat the validation immediately before every spawn, hot reload, and crash restart. Do not treat selecting the workspace as blanket approval for all future command-bearing revisions.