From 1176bf6d60adb5da9401c6941917f48c2af720b2 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 21 Apr 2026 09:12:26 -0400 Subject: [PATCH] fix(agent): shell-quote detached MCP launch commands Quote each argv element and the wrapped sh -c payload so detached MCP server startup cannot be broken by embedded quotes or shell metacharacters. --- lib/crates/fabro-agent/src/session.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/crates/fabro-agent/src/session.rs b/lib/crates/fabro-agent/src/session.rs index f50eec2ba..673b2230c 100644 --- a/lib/crates/fabro-agent/src/session.rs +++ b/lib/crates/fabro-agent/src/session.rs @@ -253,12 +253,19 @@ impl Session { ) -> Result<(String, std::collections::HashMap), String> { let sandbox = self.sandbox.as_ref(); - let cmd_str = command.join(" "); + let cmd_str = command + .iter() + .map(|arg| fabro_sandbox::shell_quote(arg)) + .collect::>() + .join(" "); - // Launch the server detached with setsid so Daytona's exec doesn't block + // Launch the server detached with setsid so Daytona's exec doesn't block. + // shell_quote the inner command for the outer `sh -c` so a single quote + // or metacharacter in any argv element can't break out of the wrapper. + let inner = format!("{cmd_str} > /tmp/mcp_server_stdout.log 2>/tmp/mcp_server_stderr.log"); let launch_script = format!( - "setsid sh -c '{cmd_str} > /tmp/mcp_server_stdout.log 2>/tmp/mcp_server_stderr.log' \ - /dev/null 2>&1 &\necho $!" + "setsid sh -c {quoted} /dev/null 2>&1 &\necho $!", + quoted = fabro_sandbox::shell_quote(&inner) ); let env_ref = if env.is_empty() { None } else { Some(env) }; let launch_result = sandbox