paperclipai/paperclip · critical

Daytona syncOut refusing tarball member that escapes the ext

Error message

Daytona syncOut refusing tarball member that escapes the extraction dir: ${name}

What it means

Thrown by assertTarballEntriesConfined when a tarball member name (after stripping trailing slashes) escapes the extraction directory: it is absolute, equals '..', or begins with '../'. This is a path-traversal guard run against an untrusted, sandbox-authored archive before the host extracts it, preventing writes outside the target tree.

Source

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

      throw new Error(`Daytona syncOut refusing tarball with an unparseable entry listing: ${line}`);
    }
    const typeFlag = match[1][0];
    let name = match[2];
    let linkTarget: string | null = null;
    if (typeFlag === "l") {
      const idx = name.indexOf(" -> ");
      if (idx === -1) throw new Error(`Daytona syncOut refusing unparseable symlink entry: ${line}`);
      linkTarget = name.slice(idx + " -> ".length);
      name = name.slice(0, idx);
    } else if (typeFlag === "h") {
      const idx = name.indexOf(" link to ");
      if (idx === -1) throw new Error(`Daytona syncOut refusing unparseable hardlink entry: ${line}`);
      linkTarget = name.slice(idx + " link to ".length);
      name = name.slice(0, idx);
    }
    const cleanName = name.replace(/\/+$/, "");
    if (cleanName.length > 0 && posixPathEscapes(cleanName)) {
      throw new Error(`Daytona syncOut refusing tarball member that escapes the extraction dir: ${name}`);
    }
    if (linkTarget !== null) {
      const resolved = path.posix.join(path.posix.dirname(cleanName), linkTarget);
      if (path.posix.isAbsolute(linkTarget) || posixPathEscapes(resolved)) {
        throw new Error(
          `Daytona syncOut refusing tarball link whose target escapes the extraction dir: ${name} -> ${linkTarget}`,
        );
      }
    }
  }
}

async function extractHostTarball(input: { archivePath: string; localDir: string }): Promise<void> {
  // The archive is sandbox-authored and untrusted: validate every member (and
  // link target) is confined before letting host-side tar write a single byte.
  await assertTarballEntriesConfined(input.archivePath);
  await fs.mkdir(input.localDir, { recursive: true });
  await execFileAsync("tar", ["-xf", input.archivePath, "-C", input.localDir], {

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Inspect the offending member `name` in the error message to confirm which sandbox file produced the escaping path.
  2. Fix the sandbox-side process so it only writes files within the workspace remote dir (no absolute or ../ paths).
  3. If the entry is legitimate, ensure the syncOut source mapping is rooted inside the confinement directory.
  4. Re-run syncOut after correcting the source tree; the guard will pass once all members are confined.

Example fix

// before: sandbox writes /etc/override into synced dir
// after: sandbox writes only under $remoteCwd
process.chdir(remoteCwd); fs.writeFileSync('./local-file', data);
Defensive patterns

Strategy: validation

Validate before calling

function memberIsConfined(name: string): boolean {
  const clean = name.replace(/\/+$/, '');
  if (clean.length === 0) return true;
  const norm = path.posix.normalize(clean);
  return !(norm === '..' || norm.startsWith('../') || path.posix.isAbsolute(norm));
}

Try / catch

try {
  await extractHostTarball({ archivePath, localDir });
} catch (e) {
  if (e instanceof Error && e.message.includes('escapes the extraction dir')) {
    // quarantine the archive; do not extract anywhere on the host
  }
  throw e;
}

Prevention

When it happens

Trigger: A syncOut tarball contains an entry whose cleaned name is an absolute POSIX path, '..', or starts with '../'. The check posixPathEscapes normalizes the path and rejects any breakout.

Common situations: A malicious or buggy sandbox writes files with absolute paths or parent-directory traversal into the tar; a misconfigured source path that resolves outside the workspace remote dir; symlink/hardlink redirection creating out-of-tree member names.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/638e68a04c6f3169. Report an issue: GitHub.