{"record":{"id":"bc67c8f937003d60","repo":"stablyai/orca","slug":"upload-source-escapes-selected-directory-candid","errorCode":null,"errorMessage":"Upload source escapes selected directory: ${candidatePath}","messagePattern":"Upload source escapes selected directory: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/filesystem-import-ssh-directory.ts","lineNumber":104,"sourceCode":"  left: number | bigint | undefined,\n  right: number | bigint | undefined\n): boolean {\n  const leftKnown = left !== undefined && left !== 0 && left !== 0n\n  const rightKnown = right !== undefined && right !== 0 && right !== 0n\n  return leftKnown && rightKnown && left !== right\n}\n\nasync function assertLocalUploadPathInsideRoot(\n  rootRealPath: string,\n  candidatePath: string\n): Promise<void> {\n  const candidateRealPath = await realpath(candidatePath)\n  const relativeToRoot = relative(rootRealPath, candidateRealPath)\n  if (\n    relativeToRoot !== '' &&\n    (relativeToRoot === '..' || relativeToRoot.startsWith(`..${sep}`) || isAbsolute(relativeToRoot))\n  ) {\n    throw new Error(`Upload source escapes selected directory: ${candidatePath}`)\n  }\n}\n","sourceCodeStart":86,"sourceCodeEnd":107,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/filesystem-import-ssh-directory.ts#L86-L107","documentation":"Thrown by assertLocalUploadPathInsideRoot() during recursive SSH directory upload. For each visited path it resolves realpath(candidate) and computes its path relative to rootRealPath; if that relative path is '..', starts with '../', or is absolute, the candidate resolves outside the upload root and the import is rejected. This is a security guard against symlink-mediated path traversal: a child entry whose realpath target escapes the selected directory.","triggerScenarios":"uploadSshImportDirectory walks a directory that contains a symlinked child (or a child reachable through a symlinked intermediate) whose realpath resolves outside rootRealPath. Because realpath follows links, any entry pointing out of the root trips the check, even before the later symlink skip.","commonSituations":"Dropped/imported directory contains symlinks to /etc, a sibling project, or an absolute outside path; a node_modules-style symlinked package whose real target lives outside the dropped root; a directory whose parent component is itself a symlink escaping the root.","solutions":["Remove or un-symlink the escaping entry from the source tree before importing.","Restructure so external targets are copied inside the upload root rather than symlinked out.","If the escape is intentional, copy the referenced content into the tree instead of importing the symlink."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Pre-scan for escaping symlinks before calling uploadSshImportDirectory\nimport { realpath, readdir } from 'node:fs/promises'\nimport { relative, sep } from 'node:path'\nasync function hasEscapingSymlink(rootReal: string, dir: string): Promise<boolean> {\n  for (const e of await readdir(dir, { withFileTypes: true })) {\n    const child = joinPath(dir, e.name)\n    if (e.isSymbolicLink()) {\n      const rel = relative(rootReal, await realpath(child))\n      if (rel === '..' || rel.startsWith('..' + sep)) return true\n    }\n    if (e.isDirectory() && await hasEscapingSymlink(rootReal, child)) return true\n  }\n  return false\n}","typeGuard":null,"tryCatchPattern":"try {\n  await uploadSshImportDirectory(provider, session, localDir, remoteDir, root, flavor, assert)\n} catch (e) {\n  if (e instanceof Error && /escapes selected directory/.test(e.message)) {\n    // report which path escaped and abort the import for this source\n  } else throw e\n}","preventionTips":["Run a realpath-based escape pre-scan before upload and reject escaping sources in the UI.","Teach users that symlinked children pointing outside the dropped root are not uploadable.","Copy external symlink targets into the tree rather than linking them."],"tags":["security","path-traversal","symlink","upload","ssh"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}