Skip to content

Workspace LLM.config.json launches MCP commands without trust or content-change confirmation #36

Description

@glmgbj233

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

  1. Use a trusted copy or installed version of Clouds_Coder.py. Create a separate workspace and make it the current directory.
  2. 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')"
      ]
    }
  }
}
  1. 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
  1. 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.

  1. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions