paperclipai/paperclip · critical
Daytona syncOut refusing unparseable symlink entry: ${line}
Error message
Daytona syncOut refusing unparseable symlink entry: ${line} What it means
Thrown by `assertTarballEntriesConfined` (file-sync.ts:210) when a tar entry whose permission type-flag starts with `l` (symlink) does not contain the `" -> "` separator that delimits the link target in GNU `tar -tvf` output. Without the target, the guard cannot verify the symlink stays inside the extraction dir, so it refuses the entry closed.
Source
Thrown at packages/plugins/sandbox-providers/daytona/src/file-sync.ts:210
*/
async function assertTarballEntriesConfined(archivePath: string): Promise<void> {
const { stdout } = await execFileAsync("tar", ["-tvf", archivePath], {
env: { ...process.env, COPYFILE_DISABLE: "1" },
maxBuffer: 32 * 1024 * 1024,
});
const lines = stdout.split("\n").filter((line) => line.trim().length > 0);
for (const line of lines) {
// GNU tar -tvf: "<perms> <owner>/<group> <size> <date> <time> <name>[ -> target]".
const match = line.match(/^(\S+)\s+\S+\s+\d+\s+\S+\s+\S+\s+(.*)$/);
if (!match) {
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}`,
);View on GitHub (pinned to 67001ec6eb)
Solutions
- Use GNU tar in the sandbox so symlink entries render as `... name -> target`.
- Avoid filenames containing newlines in synced-out trees (sanitize before tar).
- Re-pack the archive with a compatible tar implementation before outbound sync.
Defensive patterns
Strategy: try-catch
Validate before calling
// Reject filenames containing newlines before syncOut so tar -tvf lines stay parseable.
function hasNewlineInName(name) { return /[\r\n]/.test(name); } Try / catch
try {
await performSyncOut({ sandbox, operations, remoteDir, timeoutSeconds });
} catch (err) {
if (err instanceof Error && /unparseable symlink entry/.test(err.message)) {
// ensure GNU tar in sandbox; strip/escape filenames with newlines; then retry
} else throw err;
} Prevention
- Use GNU tar so symlink entries render `name -> target`.
- Sanitize synced-out filenames to exclude embedded newlines.
- Never weaken the symlink-target check; it blocks extraction-dir escapes.
When it happens
Trigger: An untrusted sandbox-authored tarball contains a symlink entry whose verbose listing line has a leading `l` perm flag but no `" -> <target>"` suffix — e.g. a truncated line, a filename literally containing newlines that split the entry, or a non-GNU tar emitting symlinks differently.
Common situations: BSD tar or a different tar implementation formats symlinks without the ` -> ` marker; a filename with embedded newlines breaks the per-line parse; or a deliberately crafted archive to confuse the confinement check.
Related errors
- Daytona syncOut refusing tarball with an unparseable entry l
- Daytona syncOut refusing tarball link whose target escapes t
- Daytona sync ${label} path is not a confined absolute path:
- Daytona sync ${label} path escapes the workspace remote dir:
- Daytona syncOut refusing unparseable hardlink entry: ${line}
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/9ce30a7971b3aeca.
Report an issue: GitHub.