{"record":{"id":"f073ba23d0ab8170","repo":"alibaba/open-code-review","slug":"file-path-q-is-outside-repository","errorCode":null,"errorMessage":"file path %q is outside repository","messagePattern":"file path %q is outside repository","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/diff/workspace_file.go","lineNumber":25,"sourceCode":"\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/alibaba/open-code-review/internal/pathutil\"\n)\n\nfunc readWorkspaceFileForDiff(repoDir, relPath string) ([]byte, error) {\n\trepoRoot, err := pathutil.CanonicalPath(repoDir)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"resolve repository path %q: %w\", repoDir, err)\n\t}\n\tif filepath.IsAbs(relPath) {\n\t\treturn nil, fmt.Errorf(\"file path %q must be relative, not absolute\", relPath)\n\t}\n\n\tfullPath := filepath.Join(repoRoot, relPath)\n\tif !pathutil.WithinBase(repoRoot, fullPath) {\n\t\treturn nil, fmt.Errorf(\"file path %q is outside repository\", relPath)\n\t}\n\n\tparent, err := filepath.EvalSymlinks(filepath.Dir(fullPath))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"resolve parent path for %q: %w\", relPath, err)\n\t}\n\tif !pathutil.WithinBase(repoRoot, parent) {\n\t\treturn nil, fmt.Errorf(\"file path %q is outside repository\", relPath)\n\t}\n\n\tinfo, err := os.Lstat(fullPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"stat file %q: %w\", relPath, err)\n\t}\n\tif info.IsDir() {\n\t\treturn nil, fmt.Errorf(\"file path %q is a directory\", relPath)\n\t}\n\tif info.Mode()&os.ModeSymlink != 0 {","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/diff/workspace_file.go#L7-L43","documentation":"Path-containment guard: after joining the repo root with the relative path, the result (or its symlink-resolved parent) lies outside the repository. This blocks path traversal like ../../etc/passwd from reading arbitrary files as 'workspace diffs'.","triggerScenarios":"Thrown at internal/diff/workspace_file.go:25 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Verify the path stays inside the repository after joining with the repo root","Do not use '..' or symlink tricks to escape the repo root; the check runs both before and after symlink resolution","If the file genuinely lives outside the repo, it is not reviewable as a workspace change"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}