{"record":{"id":"f454186879265101","repo":"stablyai/orca","slug":"access-denied-invalid-worktree-path","errorCode":null,"errorMessage":"Access denied: invalid worktree path","messagePattern":"Access denied: invalid worktree path","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/filesystem-auth.ts","lineNumber":412,"sourceCode":"  // Why: linked worktrees are already git-trusted; reuse the cached root index so reads don't spawn `git worktree list` each time.\n  return (\n    isRegisteredWorktreePath(targetPath) ||\n    (await isPathAllowedByCanonicalRegisteredRoot(targetPath, options.canonicalSourcePath))\n  )\n}\n\n/**\n * Resolve and verify that a worktree path belongs to a registered repo.\n *\n * Why not resolveAuthorizedPath: linked worktrees can live outside repo/workspace roots; git trusts exact `git worktree list` registration, not containment.\n */\nexport async function resolveRegisteredWorktreePath(\n  worktreePath: string,\n  store: Store\n): Promise<string> {\n  // Reject malformed paths (null byte) early to prevent probing via realpath.\n  if (!worktreePath || worktreePath.includes('\\0')) {\n    throw new Error('Access denied: invalid worktree path')\n  }\n\n  const resolvedTarget = resolve(worktreePath)\n  if (registeredWorktreeRoots.has(resolvedTarget) || isRepoRoot(store.getRepos(), resolvedTarget)) {\n    return resolvedTarget\n  }\n\n  if (registeredWorktreeRootsDirty) {\n    await ensureAuthorizedRootsCache(store)\n  }\n\n  if (registeredWorktreeRoots.has(resolvedTarget)) {\n    return resolvedTarget\n  }\n\n  // Resolve symlinks only after the cheap registered-root check: on macOS realpath() can trigger TCC prompts.\n  const normalizedTarget = await normalizeExistingPath(resolvedTarget)\n  if (registeredWorktreeRoots.has(normalizedTarget)) {","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/filesystem-auth.ts#L394-L430","documentation":"Input-validation guard at the top of `resolveRegisteredWorktreePath`. It rejects a worktree path that is empty or contains a NUL byte before any filesystem call. The early rejection prevents probing the filesystem via `realpath` with maliciously crafted paths (NUL injection / empty-path behavior).","triggerScenarios":"Calling `resolveRegisteredWorktreePath(worktreePath, store)` with `worktreePath` equal to `''`, `undefined`-coerced-to-empty, or any string containing `\\0`.","commonSituations":"Renderer sent an empty worktree path (uninitialized field); a NUL byte injected via a malformed message or tampered input; a code path that forgot to default the worktree path before calling.","solutions":["Validate the worktree path is a non-empty string with no NUL bytes before invoking the IPC handler.","Ensure callers always derive the worktree path from a known repo/worktree registration rather than user-typed input.","Return a typed error to the renderer when the path is missing instead of forwarding it to main."],"exampleFix":"// before\nawait ipcRenderer.invoke('fs:worktreeResolve', maybeUndefinedPath)\n\n// after\nif (!maybeUndefinedPath || maybeUndefinedPath.includes('\\0')) {\n  throw new Error('worktree path is required')\n}\nawait ipcRenderer.invoke('fs:worktreeResolve', maybeUndefinedPath)","handlingStrategy":"validation","validationCode":"// Reject empty/NUL paths at the renderer before they reach main.\nfunction assertWorktreePath(p: unknown): asserts p is string {\n  if (typeof p !== 'string' || p.length === 0 || p.includes('\\0')) {\n    throw new Error('worktree path is required and must not contain NUL bytes')\n  }\n}\nassertWorktreePath(worktreePath)\nawait ipcRenderer.invoke('fs:worktreeResolve', worktreePath)","typeGuard":"function isValidWorktreePath(p: unknown): p is string {\n  return typeof p === 'string' && p.length > 0 && !p.includes('\\0')\n}","tryCatchPattern":"try {\n  await resolveRegisteredWorktreePath(worktreePath, store)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Access denied: invalid worktree path') {\n    // caller passed empty/NUL input; fix the source of the path\n    throw new InvalidInputError(e.message)\n  }\n  throw e\n}","preventionTips":["Validate worktree paths are non-empty strings with no NUL bytes before invoking IPC.","Derive worktree paths from repo registration, never from untrusted user input.","Treat a NUL byte in any path argument as a hard error at the trust boundary."],"tags":["filesystem","security-boundary","input-validation","worktree","null-byte"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}