{"record":{"id":"c0b3210d5055349a","repo":"paperclipai/paperclip","slug":"daytona-sync-label-path-escapes-the-workspace-r","errorCode":null,"errorMessage":"Daytona sync ${label} path escapes the workspace remote dir: ${candidate}","messagePattern":"Daytona sync (.+?) path escapes the workspace remote dir: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/plugins/sandbox-providers/daytona/src/file-sync.ts","lineNumber":121,"sourceCode":" * orchestrator's own confinement. Every sandbox-side path (the sync target for\n * inbound, the sync source for outbound) MUST canonicalize inside the workspace\n * remote dir; absolute escapes and `..` traversal are rejected fail-closed before\n * any bytes move. Sandbox paths on the server are POSIX.\n */\nexport function assertConfinedSandboxPath(remoteDir: string, candidate: string, label: string): void {\n  const normalizedRoot = path.posix.normalize(remoteDir);\n  const normalized = path.posix.normalize(candidate);\n  if (\n    !path.posix.isAbsolute(normalized) ||\n    normalized === \"..\" ||\n    normalized.includes(\"/../\") ||\n    normalized.endsWith(\"/..\")\n  ) {\n    throw new Error(`Daytona sync ${label} path is not a confined absolute path: ${candidate}`);\n  }\n  const prefix = normalizedRoot.endsWith(\"/\") ? normalizedRoot : `${normalizedRoot}/`;\n  if (normalized !== normalizedRoot && !normalized.startsWith(prefix)) {\n    throw new Error(`Daytona sync ${label} path escapes the workspace remote dir: ${candidate}`);\n  }\n}\n\nasync function withHostTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {\n  const dir = await fs.mkdtemp(path.join(os.tmpdir(), \"paperclip-daytona-sync-\"));\n  try {\n    return await fn(dir);\n  } finally {\n    await fs.rm(dir, { recursive: true, force: true }).catch(() => undefined);\n  }\n}\n\n/**\n * Build a host-side tarball of a directory, mirroring the runtime's own\n * `createTarballFromDirectory`: archive top-level entries by name (no \".\" self\n * entry), suppress AppleDouble/xattr sidecars, honor `exclude`, and reproduce the\n * `followSymlinks` → `-h` mapping so the native path is observationally identical\n * to the base64 fallback's tar.","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/sandbox-providers/daytona/src/file-sync.ts#L103-L139","documentation":"Thrown by `assertConfinedSandboxPath` (file-sync.ts:121) — the second fail-closed check — when the candidate path is absolute and free of `..` but does NOT equal the workspace `remoteDir` and does not start with `remoteDir + \"/\"`. I.e. the path is absolute but outside the permitted workspace root, so a transfer would read/write outside confinement.","triggerScenarios":"A sync mapping or post-upload command `cwd` points to an absolute path outside the workspace remote dir — e.g. `/etc/...`, `/root/...`, or a different workspace's directory. The lexical check (536) passed (absolute, no traversal) but this prefix check rejects the escape.","commonSituations":"Cross-workspace path leakage (using another workspace's remoteDir), a hard-coded absolute path in config, or untrusted input that resolves under a sibling root rather than the current workspace's remote dir.","solutions":["Scope every path to the current workspace's `remoteDir` prefix; build target/source paths as `remoteDir`-rooted.","Confirm the `remoteDir` passed to the sync matches the workspace the paths belong to.","Reject any caller-supplied absolute path that is not under the active remote dir."],"exampleFix":"// before\ncwd: \"/shared/build\" // outside remoteDir\n// after\ncwd: `${remoteDir}/build`","handlingStrategy":"validation","validationCode":"import path from \"node:path\";\nfunction assertInsideRoot(remoteDir, candidate) {\n  const root = path.posix.normalize(remoteDir);\n  const n = path.posix.normalize(candidate);\n  const prefix = root.endsWith(\"/\") ? root : `${root}/`;\n  if (n !== root && !n.startsWith(prefix)) {\n    throw new Error(`path escapes workspace remote dir: ${candidate}`);\n  }\n  return n;\n}","typeGuard":"function isInsideRemoteRoot(remoteDir: string, candidate: string): boolean {\n  const root = path.posix.normalize(remoteDir);\n  const n = path.posix.normalize(candidate);\n  const prefix = root.endsWith(\"/\") ? root : `${root}/`;\n  return n === root || n.startsWith(prefix);\n}","tryCatchPattern":null,"preventionTips":["Derive every sync path from the active workspace remoteDir, never hard-code absolutes.","Do not mix paths across workspaces; re-resolve remoteDir per workspace.","Treat this throw as a security stop — never widen remoteDir to silence it."],"tags":["daytona","sandbox","security","path-traversal","validation","file-sync"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}