Hmbown/CodeWhale · error
MCP config path cannot contain '..' components
Error message
MCP config path cannot contain '..' components
What it means
The same validator rejects any config path containing a ParentDir ('..') component, regardless of whether it would still resolve somewhere legal. It is a deliberate security guard for user- and plugin-supplied MCP config paths: traversal is never interpreted, only refused.
Source
Thrown at crates/tui/src/mcp.rs:54
use self::stdio::{STDIO_SHUTDOWN_GRACE, StderrTail};
use self::wire::{is_mcp_stale_session_body, is_mcp_stale_session_error};
use crate::network_policy::{Decision, NetworkPolicyDecider, host_from_url};
use crate::utils::write_atomic;
// === Error diagnostics helpers (#71) ===
/// Bytes of a non-2xx response body to surface in connection errors.
const ERROR_BODY_PREVIEW_BYTES: usize = 200;
fn validate_mcp_config_path(path: &Path) -> Result<()> {
if path.as_os_str().is_empty() {
anyhow::bail!("MCP config path cannot be empty");
}
if path
.components()
.any(|component| matches!(component, Component::ParentDir))
{
anyhow::bail!("MCP config path cannot contain '..' components");
}
Ok(())
}
/// Expand `${NAME}` placeholders in an MCP config value from the process
/// environment. This lets secrets (API keys, bearer tokens, …) be supplied
/// through environment variables instead of being written in cleartext into
/// the MCP config file on disk.
///
/// On a missing or malformed placeholder the error names only the offending
/// variable, never the surrounding value, so a secret-bearing string is never
/// echoed into logs or error output.
fn expand_env_placeholders_with(
value: &str,
environment: Option<&crate::plugins::HostEnvironment>,
) -> Result<String> {
let mut out = String::new();
let mut rest = value;View on GitHub (pinned to 8880682c63)
Solutions
- Use an absolute path written out in full, with no '..' segments
- Normalize the path first (canonicalize, or lexical normalization) so it contains no ParentDir components, then pass the normalized form
- Restructure the setup so the MCP config lives at a fixed location referenced absolutely
Example fix
// before
let p = config_root.join("../../../shared/mcp.json"); // contains ParentDir
// after: normalize lexically to an absolute, '..'-free path
let p = lexically_normalize(config_root.join("../../../shared/mcp.json")); Defensive patterns
Strategy: validation
Validate before calling
// Reject or normalize before handing the path to the MCP layer
use std::path::Component;
fn safe_mcp_path(p: &std::path::Path) -> Option<std::path::PathBuf> {
if p.as_os_str().is_empty() {
return None;
}
let mut out = std::path::PathBuf::new();
for c in p.components() {
match c {
Component::ParentDir => return None, // or lexically pop()
other => out.push(other.as_os_str()),
}
}
Some(out)
} Prevention
- Canonicalize user-supplied config paths at the input boundary
- Store absolute paths in automation and dotfiles
- Treat any '..' in a config path as a configuration bug, not a convenience
When it happens
Trigger: Config paths like ../shared/mcp.json, /etc/codewhale/../../home/user/mcp.json, or paths built by joining user input that carries '..' segments.
Common situations: Sharing configs across repos with ../../-style relative paths, dotfile or symlink layouts expressed with '..', automation tools emitting paths with redundant parent segments.
Related errors
- Invalid auto_review.allow[{index}].action_kind '{action_kind
- Invalid sandbox_mode '{mode}': expected read-only, workspace
- MCP config path cannot be empty
- invalid environment placeholder in MCP config value
- reviewed plugin MCP endpoint must not contain user informati
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/3542e71be4719ae9.
Report an issue: GitHub.