alibaba/open-code-review · error

file path %q is outside repository

Error message

file path %q is outside repository

What it means

Security guard error from FileReader.resolveWorkspacePath: after joining the path onto the repository root (and again after symlink resolution), pathutil.WithinBase determines the resulting path is not contained within the repository. This is a path-traversal containment check, so requests like '../secrets' or symlinked escapes are rejected with 'file path %q is outside repository'.

Source

Thrown at internal/tool/filereader.go:102

	if err != nil {
		return "", err
	}
	content, err := os.ReadFile(fullPath)
	if err != nil {
		return "", fmt.Errorf("read file %q: %w", path, err)
	}
	return string(content), nil
}

func (fr *FileReader) resolveWorkspacePath(path string) (string, error) {
	repoRoot, err := pathutil.CanonicalPath(fr.RepoDir)
	if err != nil {
		return "", fmt.Errorf("resolve repository path %q: %w", fr.RepoDir, err)
	}

	fullPath := filepath.Join(repoRoot, path)
	if !pathutil.WithinBase(repoRoot, fullPath) {
		return "", fmt.Errorf("file path %q is outside repository", path)
	}

	resolvedPath, err := filepath.EvalSymlinks(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			return fullPath, nil
		}
		return "", fmt.Errorf("resolve file %q: %w", path, err)
	}
	if !pathutil.WithinBase(repoRoot, resolvedPath) {
		return "", fmt.Errorf("file path %q is outside repository", path)
	}
	return resolvedPath, nil
}

func (fr *FileReader) readFromGitShow(parentCtx context.Context, path string) (string, error) {
	ctx, cancel := context.WithTimeout(parentCtx, 30*time.Second)
	defer cancel()

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Pass a repository-relative path without ../ components (filepath.Rel against the repo root helps).
  2. For symlinked files, either move the real file inside the repository or read it via the git ref modes (range/commit), which use git show instead of the filesystem.
  3. Sanitize/normalize user-supplied paths before handing them to the tool and check they stay under the repo root.

Example fix

// before: escapes the repository
fr.Read(ctx, "../../etc/passwd")
// after: repo-relative path
fr.Read(ctx, "internal/tool/filereader.go")
Defensive patterns

Strategy: validation

Validate before calling

abs, _ := filepath.Abs(filepath.Join(repoRoot, userInput))
if !strings.HasPrefix(abs, repoRoot+string(os.PathSeparator)) {
    return fmt.Errorf("refusing path escaping repo: %s", userInput)
}

Type guard

func containedIn(base, p string) bool { abs, err := filepath.Abs(p); if err != nil { return false }; rel, err := filepath.Rel(base, abs); return err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(os.PathSeparator)) }

Try / catch

content, err := fr.Read(ctx, rel)
if err != nil && strings.Contains(err.Error(), "outside repository") {
    log.Warn("path traversal attempt blocked; using repo-relative fallback")
    return fr.Read(ctx, filepath.FromSlash(sanitizedRel))
}

Prevention

When it happens

Trigger: Calling Read/ReadLines in workspace mode with a path containing ../ segments that escape the repo root, an absolute path treated as an escape, or a symlink inside the repo pointing to a target outside the repository.

Common situations: Agent attempting to read /etc/passwd via traversal; a repository containing symlinks to shared libraries outside the tree; test fixtures joining user-supplied paths onto the root without sanitizing.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/b2e2bfbcb017ed6c. Report an issue: GitHub.