{"record":{"id":"615b0cf047aaffe0","repo":"modelcontextprotocol/servers","slug":"invalid-path-f","errorCode":null,"errorMessage":"Invalid path: '{f}'","messagePattern":"Invalid path: '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/git/src/mcp_server_git/server.py","lineNumber":144,"sourceCode":"    return repo.git.diff(f\"--unified={context_lines}\", target)\n\ndef git_commit(repo: git.Repo, message: str) -> str:\n    commit = repo.index.commit(message)\n    return f\"Changes committed successfully with hash {commit.hexsha}\"\n\ndef git_add(repo: git.Repo, files: list[str]) -> str:\n    if files == [\".\"]:\n        repo.git.add(\".\")\n    else:\n        # Defense in depth: validate each path resolves within the repository\n        # working tree to prevent path traversal (e.g. '../../etc/passwd' or an\n        # absolute path) from staging files outside repository boundaries.\n        repo_root = Path(repo.working_dir).resolve()\n        for f in files:\n            try:\n                resolved = (repo_root / f).resolve()\n            except (OSError, RuntimeError):\n                raise ValueError(f\"Invalid path: '{f}'\")\n            try:\n                resolved.relative_to(repo_root)\n            except ValueError:\n                raise ValueError(\n                    f\"Path '{f}' is outside the repository '{repo_root}'\"\n                )\n        # Use '--' to prevent files starting with '-' from being interpreted as options\n        repo.git.add(\"--\", *files)\n    return \"Files staged successfully\"\n\ndef git_reset(repo: git.Repo) -> str:\n    repo.index.reset()\n    return \"All staged changes reset\"\n\ndef git_log(repo: git.Repo, max_count: int = 10, start_timestamp: Optional[str] = None, end_timestamp: Optional[str] = None) -> list[str]:\n    if start_timestamp or end_timestamp:\n        # Defense in depth: reject timestamps starting with '-' to prevent flag injection\n        if start_timestamp and start_timestamp.startswith(\"-\"):","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/modelcontextprotocol/servers/blob/76d64c822f5125032f89eb71dbdb94e42b434821/src/git/src/mcp_server_git/server.py#L126-L162","documentation":"In git_add(), each file path is resolved via (repo_root / f).resolve(); an OSError or RuntimeError (broken symlink, symlink loop, path with null bytes or illegal characters, permission error during resolution) is caught and rethrown as ValueError 'Invalid path: ...'. This is the resolve step, before the inside-repo check.","triggerScenarios":"A staged path is a dangling symlink; a symlink forms a loop; the path contains illegal characters or null bytes; resolve() hits a permissions error.","commonSituations":"Broken symlinks left in the working tree; OS-level path quirks; paths from untrusted input containing control characters.","solutions":["Verify the path exists and is not a broken symlink before staging.","Remove or repair the offending symlink.","Sanitize paths of null bytes and illegal characters before calling."],"exampleFix":"# before\ngit_add(repo, files=['link-to-nowhere'])  # dangling symlink -> ValueError\n\n# after\ndef clean_add(repo, files):\n    root = Path(repo.working_dir).resolve()\n    ok = [f for f in files if (root / f).exists()]\n    return git_add(repo, ok)","handlingStrategy":"validation","validationCode":"from pathlib import Path\ndef resolvable(repo, f: str) -> bool:\n    try:\n        (Path(repo.working_dir).resolve() / f).resolve()\n        return True\n    except (OSError, RuntimeError):\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    git_add(repo, files)\nexcept ValueError as e:\n    if e.args[0].startswith('Invalid path:'):\n        # drop/repair the offending path and retry\n    raise","preventionTips":["Check paths exist and are not broken symlinks before staging.","Sanitize input of null bytes and illegal characters.","Operate only on paths returned by your directory listing."],"tags":["git","python","path","symlink","validation"],"backgroundTag":null,"analyzedSha":"76d64c822f5125032f89eb71dbdb94e42b434821","analyzedAt":"2026-08-12T10:02:41.718Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}