Hmbown/CodeWhale · error
reviewed plugin MCP path escaped its staged root
Error message
reviewed plugin MCP path escaped its staged root
What it means
resolve_plugin_mcp_cwd resolves a reviewed plugin MCP server's cwd (default: the plugin's staged root; relative cwds are joined onto it, absolute ones taken as-is), canonicalizes it, and requires the result to stay under the plugin's staged path. Otherwise the reviewed plugin would spawn its server process outside the reviewed sandbox, so the config is rejected.
Source
Thrown at crates/tui/src/mcp.rs:3816
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");
}
Ok(resolved)
}
fn workspace_allows_project_mcp_config(workspace: &Path) -> bool {
crate::config::is_workspace_trusted(workspace)
}
fn checked_workspace_mcp_config_path(workspace: &Path) -> Result<PathBuf> {
Ok(checked_workspace_path(workspace)?
.join(".codewhale")
.join("mcp.json"))
}
fn checked_workspace_path(workspace: &Path) -> Result<PathBuf> {
if workspace.as_os_str().is_empty() {
anyhow::bail!("workspace path cannot be empty");
}View on GitHub (pinned to 8880682c63)
Solutions
- Set cwd to '.' or a subdirectory of the plugin root in the plugin manifest
- Drop absolute cwd values - reviewed plugins must run inside their staged tree
- Re-stage the plugin after fixing the manifest and re-review it
Example fix
// before (plugin manifest) "cwd": "/home/me/projects/my-plugin" // after "cwd": "."
Defensive patterns
Strategy: validation
Validate before calling
// Validate plugin cwd containment before registering the server: let resolved = cwd_candidate.canonicalize().unwrap_or_else(|_| normalize_path_components(&cwd_candidate)); anyhow::ensure!(resolved.starts_with(&plugin_staged_root), "plugin cwd escapes staged root");
Type guard
fn plugin_cwd_within_root(cwd: &std::path::Path, root: &std::path::Path) -> bool {
cwd.canonicalize()
.map(|c| c.starts_with(root))
.unwrap_or_else(|_| normalize_path_components(cwd).starts_with(root))
} Prevention
- Default reviewed plugin servers to cwd '.' inside the staged tree
- Never ship absolute cwd paths in plugin manifests
- Test plugins from their staged location, not the source checkout, during review
When it happens
Trigger: A plugin manifest sets cwd to an absolute path outside the staged root, a relative '../..' path, or the staged tree contains a symlink that canonicalization resolves outside the root.
Common situations: Porting a plugin that previously ran from the repo root; a plugin assuming its cwd is the user's project directory rather than the staged tree.
Related errors
- reviewed plugin MCP argument path escaped its staged root
- MCP config path cannot contain '..' components
- reviewed plugin stdio cwd escaped its staged root
- Project MCP server cwd must stay within workspace: {}
- reviewed plugin stage could not be opened for launch
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/ffd69900cefe47a6.
Report an issue: GitHub.