Description
mcpls auto-discovers and loads ./mcpls.toml from the current working directory on startup (config/mod.rs, default config path resolution), and each [[lsp_servers]] entry's command, args, and env are passed directly to Command::new (lsp/lifecycle.rs) with no confirmation, allowlist, or sandboxing step.
Since mcpls is designed to be launched by an AI coding agent against an arbitrary working directory (e.g. a freshly cloned repository), a hostile repository can ship an mcpls.toml that spawns an arbitrary process — with attacker-controlled args and env — the moment mcpls starts, before any LSP-specific validation occurs. This is effectively code execution via git clone <hostile-repo> && <start mcpls in that directory>.
This was identified as a side finding during the security review for #174/#165 (routing config work) — it is a pre-existing gap unrelated to that PR's scope, so it wasn't fixed there.
Reproduction Steps
- Create a repository containing
mcpls.toml with an [[lsp_servers]] entry whose command points to an arbitrary executable (e.g. a script that exfiltrates data or opens a reverse shell), disguised with a plausible language_id/file_patterns.
- Clone the repository.
- Start mcpls with that directory as the workspace root (as an AI agent integration normally would).
- Observe: the configured
command executes immediately as part of server discovery/spawn, with no prompt or confirmation.
Expected Behavior
At minimum, one of:
- mcpls warns or requires explicit confirmation before executing a
command sourced from a project-local (not user/global) config file it did not create.
- A documented trust boundary: e.g. only global/user-level config (
~/.config/mcpls/mcpls.toml, $MCPLS_CONFIG) is auto-loaded without confirmation; project-local ./mcpls.toml requires an explicit opt-in flag or first-run prompt, similar to how VS Code / direnv handle untrusted workspace config.
Actual Behavior
./mcpls.toml in the current directory is auto-loaded and its command/args/env are executed unconditionally on startup.
Environment
- Version: current main (0.3.7)
- Files:
crates/mcpls-core/src/config/mod.rs (auto-load path resolution), crates/mcpls-core/src/lsp/lifecycle.rs (Command::new spawn)
Logs / Evidence
Flagged during the security-audit validation pass for PR #228 (issues #174/#165): "the config is already an arbitrary-code-execution boundary — ./mcpls.toml in the current directory is auto-loaded and its command/args/env go straight to Command::new. Cloning a hostile repository and starting mcpls in it is code execution."
Description
mcplsauto-discovers and loads./mcpls.tomlfrom the current working directory on startup (config/mod.rs, default config path resolution), and each[[lsp_servers]]entry'scommand,args, andenvare passed directly toCommand::new(lsp/lifecycle.rs) with no confirmation, allowlist, or sandboxing step.Since mcpls is designed to be launched by an AI coding agent against an arbitrary working directory (e.g. a freshly cloned repository), a hostile repository can ship an
mcpls.tomlthat spawns an arbitrary process — with attacker-controlledargsandenv— the moment mcpls starts, before any LSP-specific validation occurs. This is effectively code execution viagit clone <hostile-repo> && <start mcpls in that directory>.This was identified as a side finding during the security review for #174/#165 (routing config work) — it is a pre-existing gap unrelated to that PR's scope, so it wasn't fixed there.
Reproduction Steps
mcpls.tomlwith an[[lsp_servers]]entry whosecommandpoints to an arbitrary executable (e.g. a script that exfiltrates data or opens a reverse shell), disguised with a plausiblelanguage_id/file_patterns.commandexecutes immediately as part of server discovery/spawn, with no prompt or confirmation.Expected Behavior
At minimum, one of:
commandsourced from a project-local (not user/global) config file it did not create.~/.config/mcpls/mcpls.toml,$MCPLS_CONFIG) is auto-loaded without confirmation; project-local./mcpls.tomlrequires an explicit opt-in flag or first-run prompt, similar to how VS Code / direnv handle untrusted workspace config.Actual Behavior
./mcpls.tomlin the current directory is auto-loaded and itscommand/args/envare executed unconditionally on startup.Environment
crates/mcpls-core/src/config/mod.rs(auto-load path resolution),crates/mcpls-core/src/lsp/lifecycle.rs(Command::newspawn)Logs / Evidence
Flagged during the security-audit validation pass for PR #228 (issues #174/#165): "the config is already an arbitrary-code-execution boundary —
./mcpls.tomlin the current directory is auto-loaded and itscommand/args/envgo straight toCommand::new. Cloning a hostile repository and starting mcpls in it is code execution."