{"record":{"id":"6bdb51ea9c744238","repo":"paperclipai/paperclip","slug":"kubernetes-syncout-refusing-tarball-member-that-es","errorCode":null,"errorMessage":"Kubernetes syncOut refusing tarball member that escapes the extraction dir: ${name}","messagePattern":"Kubernetes syncOut refusing tarball member that escapes the extraction dir: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/kubernetes/src/file-sync.ts","lineNumber":399,"sourceCode":"      throw new Error(`Kubernetes syncOut refusing tarball with an unparseable entry listing: ${line}`);\n    }\n    const typeFlag = parsed.typeFlag;\n    let name = parsed.rest;\n    let linkTarget: string | null = null;\n    if (typeFlag === \"l\") {\n      const split = splitLinkEntryOnce(name, \" -> \");\n      if (!split) throw new Error(`Kubernetes syncOut refusing unparseable or ambiguous symlink entry: ${line}`);\n      name = split.name;\n      linkTarget = split.target;\n    } else if (typeFlag === \"h\") {\n      const split = splitLinkEntryOnce(name, \" link to \");\n      if (!split) throw new Error(`Kubernetes syncOut refusing unparseable or ambiguous hardlink entry: ${line}`);\n      name = split.name;\n      linkTarget = split.target;\n    }\n    const cleanName = name.replace(/\\/+$/, \"\");\n    if (cleanName.length > 0 && posixPathEscapes(cleanName)) {\n      throw new Error(`Kubernetes syncOut refusing tarball member that escapes the extraction dir: ${name}`);\n    }\n    if (linkTarget !== null) {\n      const resolved = path.posix.join(path.posix.dirname(cleanName), linkTarget);\n      if (path.posix.isAbsolute(linkTarget) || posixPathEscapes(resolved)) {\n        throw new Error(\n          `Kubernetes syncOut refusing tarball link whose target escapes the extraction dir: ${name} -> ${linkTarget}`,\n        );\n      }\n    }\n  }\n}\n\nasync function extractHostTarball(input: { archivePath: string; localDir: string }): Promise<void> {\n  // The archive is sandbox-authored and untrusted: validate every member (and\n  // link target) is confined before letting host-side tar write a single byte.\n  await assertTarballEntriesConfined(input.archivePath);\n  await fs.mkdir(input.localDir, { recursive: true });\n  await execFileAsync(\"tar\", [\"-xf\", input.archivePath, \"-C\", input.localDir], {","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/packages/plugins/sandbox-providers/kubernetes/src/file-sync.ts#L381-L417","documentation":"Error \"Kubernetes syncOut refusing tarball member that escapes the extraction dir: ${name}\" thrown in paperclipai/paperclip.","triggerScenarios":"Thrown at packages/plugins/sandbox-providers/kubernetes/src/file-sync.ts:399 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Remove path-traversal entries from the tarball; all members must extract inside the target dir."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}