From 05ee4b30d732dc4e5498bbac22ec8aece7016faf Mon Sep 17 00:00:00 2001 From: gabrielonrails <67797629+GabrielOnRails@users.noreply.github.com> Date: Fri, 14 Aug 2026 20:31:15 -0300 Subject: [PATCH] Harden delete_files MCP tool: validate paths within repo root (#1636) Mirror the path validation already performed by the commit_files tool. delete_files previously only normalized absolute paths against CWD and passed relative paths through unchecked; it now runs each path through validatePathWithinRepo, rejecting "../" traversal and symlinked escapes for consistency and defense-in-depth. Co-authored-by: Claude Opus 4.8 --- src/mcp/github-file-ops-server.ts | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/mcp/github-file-ops-server.ts b/src/mcp/github-file-ops-server.ts index 2b4906b6..0c274d5b 100644 --- a/src/mcp/github-file-ops-server.ts +++ b/src/mcp/github-file-ops-server.ts @@ -432,21 +432,18 @@ server.tool( throw new Error("GITHUB_TOKEN environment variable is required"); } - // Convert absolute paths to relative if they match CWD - const cwd = process.cwd(); - const processedPaths = paths.map((filePath) => { - if (filePath.startsWith("/")) { - if (filePath.startsWith(cwd)) { - // Strip CWD from absolute path - return filePath.slice(cwd.length + 1); - } else { - throw new Error( - `Path '${filePath}' must be relative to repository root or within current working directory`, - ); - } - } - return filePath; - }); + // Validate all paths are within the repository root and normalize them to + // repo-relative paths for the git tree entries. This mirrors the validation + // already performed by the commit_files tool and rejects path traversal + // ("../") and symlinked escapes as defense-in-depth. + const resolvedRepoDir = resolve(REPO_DIR); + const processedPaths = await Promise.all( + paths.map(async (filePath) => { + await validatePathWithinRepo(filePath, REPO_DIR); + const normalizedPath = resolve(resolvedRepoDir, filePath); + return normalizedPath.slice(resolvedRepoDir.length + 1); + }), + ); // 1. Get the branch reference (create if doesn't exist) const baseSha = await getOrCreateBranchRef(