paperclipai/paperclip · error

Daytona sync path is not a confined absolute path

Error message

Daytona sync ${label} path is not a confined absolute path: ${candidate}

What it means

Defense-in-depth confinement guard in assertConfinedSandboxPath: a Daytona file-sync path (sync target for inbound, sync source for outbound) did not canonicalize to a POSIX absolute path inside the workspace remote dir — it was relative, empty, or a bare '..'. The guard fails closed before any bytes move so sync can never address a path outside the sandbox workspace root.

Solutions

  1. Use an absolute path confined to the allowed root for the sync path.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/plugins/sandbox-providers/daytona/src/file-sync.ts:117 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-08-18). Data as JSON: /api/errors/9d38630e6db9f49b. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugins/sandbox-providers/daytona/src/file-sync.ts:121

 * path handed to `sandbox.process.executeCommand` (tar extract / `mv -f` rename)
 * MUST pass through this so a path containing shell metacharacters is transferred
 * literally, never interpreted.
 */
function shellQuote(value: string): string {
  return `'${value.replace(/'/g, `'"'"'`)}'`;
}

/**
 * Convert a POSIX numeric mode (e.g. `0o600`) to the octal string the Daytona
 * SDK's `setFilePermissions` expects (e.g. `"600"`), masked to the permission
 * bits so an accidental type flag never widens the mode.
 */
function toOctalModeString(mode: number): string {
  return (mode & 0o7777).toString(8).padStart(3, "0");
}

/**
 * Host-side complete-mediation guard applied as defense-in-depth below the
 * orchestrator's own confinement. Every sandbox-side path (the sync target for
 * inbound, the sync source for outbound) MUST canonicalize inside the workspace
 * remote dir; absolute escapes and `..` traversal are rejected fail-closed before
 * any bytes move. Sandbox paths on the server are POSIX.
 */
export function assertConfinedSandboxPath(remoteDir: string, candidate: string, label: string): void {
  const normalizedRoot = path.posix.normalize(remoteDir);
  const normalized = path.posix.normalize(candidate);
  if (
    !path.posix.isAbsolute(normalized) ||
    normalized === ".." ||
    normalized.includes("/../") ||
    normalized.endsWith("/..")
  ) {
    throw new Error(`Daytona sync ${label} path is not a confined absolute path: ${candidate}`);
  }
  const prefix = normalizedRoot.endsWith("/") ? normalizedRoot : `${normalizedRoot}/`;
  if (normalized !== normalizedRoot && !normalized.startsWith(prefix)) {

View on GitHub (pinned to 3f1d897a7c)