modelcontextprotocol/servers · error · ValueError
Path '{f}' is outside the repository '{repo_root}'
Error message
Path '{f}' is outside the repository '{repo_root}' What it means
In git_add(), after the path resolves successfully, resolved.relative_to(repo_root) raises ValueError when the path is not under the repository root (path traversal such as ../../etc/passwd, or an absolute path outside the tree). The code then stages with `git add --` to also prevent option injection. The exception type is ValueError and propagates raw to the client.
Source
Thrown at src/git/src/mcp_server_git/server.py:148
return f"Changes committed successfully with hash {commit.hexsha}"
def git_add(repo: git.Repo, files: list[str]) -> str:
if files == ["."]:
repo.git.add(".")
else:
# Defense in depth: validate each path resolves within the repository
# working tree to prevent path traversal (e.g. '../../etc/passwd' or an
# absolute path) from staging files outside repository boundaries.
repo_root = Path(repo.working_dir).resolve()
for f in files:
try:
resolved = (repo_root / f).resolve()
except (OSError, RuntimeError):
raise ValueError(f"Invalid path: '{f}'")
try:
resolved.relative_to(repo_root)
except ValueError:
raise ValueError(
f"Path '{f}' is outside the repository '{repo_root}'"
)
# Use '--' to prevent files starting with '-' from being interpreted as options
repo.git.add("--", *files)
return "Files staged successfully"
def git_reset(repo: git.Repo) -> str:
repo.index.reset()
return "All staged changes reset"
def git_log(repo: git.Repo, max_count: int = 10, start_timestamp: Optional[str] = None, end_timestamp: Optional[str] = None) -> list[str]:
if start_timestamp or end_timestamp:
# Defense in depth: reject timestamps starting with '-' to prevent flag injection
if start_timestamp and start_timestamp.startswith("-"):
raise ValueError(f"Invalid start_timestamp: '{start_timestamp}' - cannot start with '-'")
if end_timestamp and end_timestamp.startswith("-"):
raise ValueError(f"Invalid end_timestamp: '{end_timestamp}' - cannot start with '-'")
# Use git log command with date filteringView on GitHub (pinned to 76d64c822f)
Solutions
- Use paths relative to the repository root and confined to it.
- Ensure the file physically resides under the working tree.
- Reject absolute paths and any resolved path whose common prefix is not repo_root.
Example fix
# before
git_add(repo, files=['../../etc/passwd']) # -> ValueError outside repo
# after
def within_repo(repo, f):
root = Path(repo.working_dir).resolve()
return (root / f).resolve().is_relative_to(root)
git_add(repo, [f for f in files if within_repo(repo, f)]) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def within_repo(repo, f: str) -> bool:
root = Path(repo.working_dir).resolve()
try:
return (root / f).resolve().is_relative_to(root)
except (OSError, RuntimeError):
return False Try / catch
try:
git_add(repo, files)
except ValueError as e:
if 'outside the repository' in e.args[0]:
# filter out traversal paths and retry
raise Prevention
- Reject absolute paths and parent traversal (..) segments before staging.
- Resolve every path and confirm it is under repo_root.
- Treat untrusted file lists as untrusted; sanitize at the boundary.
When it happens
Trigger: Passing a relative path that escapes the working tree (../); passing an absolute path outside the repo; symlinks that resolve outside the repo.
Common situations: Adversarial path input; UI permitting absolute paths; symlink chains pointing outside the repo.
Related errors
- Invalid target: '{target}' - cannot start with '-'
- Invalid start_timestamp: '{start_timestamp}' - cannot start
- Invalid end_timestamp: '{end_timestamp}' - cannot start with
- Invalid branch name: '{branch_name}' - cannot start with '-'
- Invalid base branch: '{base_branch}' - cannot start with '-'
AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12).
Data as JSON: /api/errors/9666405fd8090e81.
Report an issue: GitHub.