{"record":{"id":"9d38630e6db9f49b","repo":"paperclipai/paperclip","slug":"daytona-sync-label-path-is-not-a-confined-absol","errorCode":null,"errorMessage":"Daytona sync ${label} path is not a confined absolute path: ${candidate}","messagePattern":"Daytona sync (.+?) path is not a confined absolute path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/plugins/sandbox-providers/daytona/src/file-sync.ts","lineNumber":117,"sourceCode":"}\n\n/**\n * Host-side complete-mediation guard applied as defense-in-depth below the\n * 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","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/sandbox-providers/daytona/src/file-sync.ts#L99-L135","documentation":"Thrown by `assertConfinedSandboxPath` (file-sync.ts:117) — a fail-closed security guard — when a candidate sandbox path is not POSIX-absolute, or normalizes to `..`, contains `/../`, or ends with `/..`. Every inbound (sync target) and outbound (sync source) path MUST canonicalize inside the workspace remote dir before any bytes move; this is the first check rejecting non-absolute or traversing paths.","triggerScenarios":"A sync file mapping supplies a `targetPath`/`sourcePath` that is relative (`\"foo\"`), dot-relative (`\"./x\"`, `\"../x\"`), or contains `..` segments after POSIX normalization. Also fires for a post-upload command `cwd` that is not absolute. The guard runs host-side before any sandbox round trip.","commonSituations":"A plugin/mapping builder constructs paths with `path.join` on a Windows host (backslashes), passes a relative repo path by mistake, or accepts untrusted user input as a sync target without absolutizing it under the remote dir.","solutions":["Ensure every sync `targetPath`/`sourcePath` and command `cwd` is POSIX-absolute (leading `/`) and resolved under the workspace `remoteDir`.","Use `path.posix.resolve(remoteDir, relativeInput)` to absolutize, then pass the result.","Reject `..` components in untrusted path input before constructing the mapping."],"exampleFix":"// before\nmapping: { sourcePath: localFile, targetPath: \"repo/file.txt\", kind: \"file\" }\n// after\nmapping: { sourcePath: localFile, targetPath: `${remoteDir}/repo/file.txt`, kind: \"file\" }","handlingStrategy":"validation","validationCode":"import path from \"node:path\";\nfunction assertConfined(remoteDir, candidate) {\n  const n = path.posix.normalize(candidate);\n  if (!path.posix.isAbsolute(n) || n === \"..\" || n.includes(\"/../\") || n.endsWith(\"/..\")) {\n    throw new Error(`path not a confined absolute path: ${candidate}`);\n  }\n  return n;\n}\n// call assertConfined(remoteDir, targetPath) BEFORE building the sync mapping","typeGuard":"function isConfinedAbsolutePath(remoteDir: string, candidate: string): boolean {\n  const n = path.posix.normalize(candidate);\n  if (!path.posix.isAbsolute(n) || n === \"..\" || n.includes(\"/../\") || n.endsWith(\"/..\")) return false;\n  const prefix = remoteDir.endsWith(\"/\") ? remoteDir : `${remoteDir}/`;\n  return n === remoteDir || n.startsWith(prefix);\n}","tryCatchPattern":null,"preventionTips":["Always build sync target/source paths as POSIX-absolute and remoteDir-rooted.","Use path.posix (not the host path module) when constructing sandbox paths.","Reject relative or '..'-containing input from untrusted callers before syncing."],"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"}