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
- Pass a repository-relative path without ../ components (filepath.Rel against the repo root helps).
- 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.
- 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
- Always sanitize user/LLM-supplied paths: strip leading '/', collapse '..', and verify containment against the repo root.
- Treat this error as a security signal — log the offending path and caller.
- Audit repositories for symlinks pointing outside the tree before enabling workspace reads.
- Use filepath.Rel to normalize any path onto the repo root before calling Read.
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
- rule file path %q escapes repo dir %q
- background file %q is a directory, not a file
- background file %q is %d bytes, exceeding the maximum of %d
- invalid max_tokens %q: must be a positive integer
- unknown config key: %s Supported keys: %s Provider fields: a
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/b2e2bfbcb017ed6c.
Report an issue: GitHub.