Hmbown/CodeWhale · error
reviewed plugin MCP argument path escaped its staged root
Error message
reviewed plugin MCP argument path escaped its staged root
What it means
For reviewed (sandboxed) plugin MCP servers, any relative command argument that names an existing path is resolved against the runtime cwd, canonicalized, and then required to stay inside the plugin's staged root directory. If the canonical path (after resolving symlinks and '..') lands outside the staging directory, the server config is rejected - a reviewed plugin cannot smuggle execution outside its staged tree via argument paths.
Source
Thrown at crates/tui/src/mcp.rs:3798
fn freeze_plugin_stdio_paths(config: &mut McpServerConfig, staged_root: &Path) -> Result<()> {
if let Some(command) = config.command.as_mut()
&& (command.contains('/') || command.contains('\\'))
{
let frozen = resolve_plugin_mcp_cwd(staged_root, Some(Path::new(command)))?;
*command = frozen.display().to_string();
}
let runtime_cwd = config.cwd.as_deref().unwrap_or(staged_root).to_path_buf();
for argument in &mut config.args {
if argument.starts_with('-') || Path::new(argument).is_absolute() {
continue;
}
let candidate = normalize_path_components(&runtime_cwd.join(argument.as_str()));
if candidate.exists() {
let frozen = candidate
.canonicalize()
.context("failed to freeze reviewed plugin MCP argument path")?;
if !frozen.starts_with(staged_root) {
anyhow::bail!("reviewed plugin MCP argument path escaped its staged root");
}
*argument = frozen.display().to_string();
}
}
Ok(())
}
fn resolve_plugin_mcp_cwd(plugin_path: &Path, cwd: Option<&Path>) -> Result<PathBuf> {
let cwd = match cwd {
Some(cwd) if cwd.is_relative() => normalize_path_components(&plugin_path.join(cwd)),
Some(cwd) => normalize_path_components(cwd),
None => plugin_path.to_path_buf(),
};
let resolved = cwd
.canonicalize()
.unwrap_or_else(|_| normalize_path_components(&cwd));
if !resolved.starts_with(plugin_path) {
anyhow::bail!("reviewed plugin MCP path escaped its staged root");View on GitHub (pinned to 8880682c63)
Solutions
- Change the plugin's args to reference files inside the plugin's staged directory only
- Remove symlinks inside the staged tree that point outside it, then re-stage and re-review the plugin
- Invoke external tools by bare name (PATH lookup) instead of file paths - PATH args skip the freeze check
Example fix
// before (plugin manifest, server args) "args": ["../../bin/helper", "--serve"] // after "args": ["./bin/helper", "--serve"]
Defensive patterns
Strategy: validation
Validate before calling
// Before enabling a reviewed plugin MCP server, verify every relative arg stays in the staged root:
for arg in &server_config.args {
if arg.starts_with('-') || std::path::Path::new(arg).is_absolute() { continue; }
let candidate = runtime_cwd.join(arg);
if candidate.exists() {
let frozen = candidate.canonicalize()?;
anyhow::ensure!(frozen.starts_with(&staged_root), "arg escapes staged root: {arg}");
}
} Type guard
fn plugin_args_within_root(args: &[String], cwd: &std::path::Path, root: &std::path::Path) -> bool {
args.iter().all(|a| {
a.starts_with('-')
|| std::path::Path::new(a).is_absolute()
|| !cwd.join(a).exists()
|| cwd.join(a).canonicalize().map(|c| c.starts_with(root)).unwrap_or(false)
})
} Prevention
- Author plugin manifests with args that only reference files inside the staged tree
- Avoid symlinks inside staged plugin directories, especially absolute or out-of-tree targets
- Re-stage and re-review the plugin after any manifest or tree change so paths are re-frozen
When it happens
Trigger: A plugin manifest passes a relative arg like '../../bin/helper', or an arg that is or crosses a symlink pointing outside the staged root, and that path exists on disk so the freeze step runs.
Common situations: A plugin that invokes bundled binaries by relative path but was staged with symlinks inside the tree; moving the staging directory so previously-fine relative paths now resolve elsewhere.
Related errors
- reviewed plugin MCP path escaped its staged root
- MCP config path cannot contain '..' components
- reviewed plugin stage could not be opened for launch
- reviewed plugin stdio cwd escaped its staged root
- Refusing to {operation} MCP server '{server_name}' from plug
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/f0f360cbec3994c1.
Report an issue: GitHub.