stablyai/orca · critical · Error
Access denied: git file path escapes the selected worktree
Error message
Access denied: git file path escapes the selected worktree
What it means
Containment check in `validateGitRelativeFilePath`: after joining, `isDescendantOrEqual(resolvedFilePath, worktreePath)` is false, meaning the resolved path is not within the worktree. This catches relative traversal such as `../../etc/passwd` that survives the join but lands outside the worktree root.
Source
Thrown at src/main/ipc/filesystem-auth.ts:537
async function normalizeExistingPath(resolvedPath: string): Promise<string> {
try {
return resolve(await realpath(resolvedPath))
} catch (error) {
if (isENOENT(error)) {
return resolvedPath
}
throw error
}
}
export function validateGitRelativeFilePath(worktreePath: string, filePath: string): string {
if (!filePath || filePath.includes('\0') || resolve(filePath) === filePath) {
throw new Error('Access denied: invalid git file path')
}
const resolvedFilePath = resolve(worktreePath, filePath)
if (!isDescendantOrEqual(resolvedFilePath, worktreePath)) {
throw new Error('Access denied: git file path escapes the selected worktree')
}
const normalizedRelativePath = relative(worktreePath, resolvedFilePath)
if (!normalizedRelativePath) {
throw new Error('Access denied: invalid git file path')
}
return normalizedRelativePath
}
View on GitHub (pinned to 1136503c6a)
Solutions
- Sanitize the path to remove `..` segments, or reject any path that would resolve above the worktree root.
- Compute the relative path using `path.relative(worktreePath, absPath)` and verify the result does not start with `..`.
- Reject renderer-supplied paths that contain `..` at the trust boundary.
Example fix
// before
validateGitRelativeFilePath(worktreePath, '../../etc/passwd')
// after
const rel = relative(worktreePath, resolve(worktreePath, userInput))
if (rel.startsWith('..')) throw new Error('path escapes worktree')
validateGitRelativeFilePath(worktreePath, rel) Defensive patterns
Strategy: validation
Validate before calling
// Strip/verify no parent traversal before validating.
const candidate = resolve(worktreePath, filePath)
const rel = relative(worktreePath, candidate)
if (rel.startsWith('..')) {
throw new Error('path escapes the worktree')
}
return validateGitRelativeFilePath(worktreePath, filePath) Type guard
function staysInsideWorktree(worktreePath: string, filePath: string): boolean {
const rel = relative(worktreePath, resolve(worktreePath, filePath))
return rel !== '' && !rel.startsWith('..')
} Try / catch
try {
return validateGitRelativeFilePath(worktreePath, filePath)
} catch (e) {
if (e instanceof Error && e.message === 'Access denied: git file path escapes the selected worktree') {
// contained `..` traversal; reject the renderer-supplied path
throw new PathTraversalError(e.message)
}
throw e
} Prevention
- Reject any renderer-supplied path containing `..` segments at the trust boundary.
- Compute paths via path.relative(worktreePath, abs) and verify the result does not start with `..`.
- Treat path-escape as a security event, not a recoverable input error.
When it happens
Trigger: Calling `validateGitRelativeFilePath(worktreePath, filePath)` with a relative path containing `..` segments that resolve above the worktree root, e.g. `../../secrets.env`.
Common situations: User- or renderer-supplied path with parent-directory traversal; a diff tool returning paths outside the worktree; symlinked content whose relative path resolves above the root; mis-computed relative path from a wrong base.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Access denied: path resolves outside allowed directories. If
- Access denied: unknown repository or worktree path
- Access denied: invalid git file path
- Clone path must be inside the destination directory
- Access denied: submodule path escapes the selected worktree
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/efa04202fb4f5445.
Report an issue: GitHub.