{"record":{"id":"0e6207d5aef84e09","repo":"paperclipai/paperclip","slug":"workspace-uploads-require-a-platform-with-confined","errorCode":null,"errorMessage":"Workspace uploads require a platform with confined file opens; use an authorized artifact reference","messagePattern":"Workspace uploads require a platform with confined file opens; use an authorized artifact reference","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/runner-api-files.ts","lineNumber":14,"sourceCode":"import { constants } from \"node:fs\";\nimport { open, type FileHandle } from \"node:fs/promises\";\nimport { isAbsolute } from \"node:path\";\n\n/** Open a previously authorized canonical path without following raced symlinks. */\nexport async function openRunnerApiWorkspaceFile(path: string): Promise<FileHandle> {\n  if (!isAbsolute(path)) throw new Error(\"Workspace file must have a canonical absolute path\");\n  if (process.platform === \"darwin\") {\n    // Darwin sys/fcntl.h: O_NOFOLLOW_ANY rejects symlinks at every component.\n    // Node does not expose this flag in fs.constants. Unsupported kernels fail\n    // closed instead of falling back to a pathname check followed by open.\n    return open(path, constants.O_RDONLY | constants.O_NONBLOCK | 0x20000000);\n  }\n  if (process.platform !== \"linux\") throw new Error(\"Workspace uploads require a platform with confined file opens; use an authorized artifact reference\");\n  const parts = path.split(\"/\").filter(Boolean);\n  if (!parts.length || parts.some(part => part === \".\" || part === \"..\")) throw new Error(\"Invalid canonical workspace path\");\n  let directory = await open(\"/\", constants.O_RDONLY | constants.O_DIRECTORY);\n  try {\n    for (const part of parts.slice(0, -1)) {\n      // Linux magic descriptor links provide openat-style directory confinement.\n      const next = await open(`/proc/self/fd/${directory.fd}/${part}`, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);\n      await directory.close();\n      directory = next;\n    }\n    return await open(`/proc/self/fd/${directory.fd}/${parts.at(-1)}`, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);\n  } finally { await directory.close(); }\n}\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/native-runtime/runner-api-files.ts#L1-L28","documentation":"On platforms other than darwin and linux, openRunnerApiWorkspaceFile throws \"Workspace uploads require a platform with confined file opens\". Confined workspace uploads rely on platform primitives (macOS O_NOFOLLOW_ANY, Linux openat-style /proc/self/fd directory links); any other OS cannot guarantee symlink-race-free opens, so the function fails closed and directs callers to use an authorized artifact reference instead.","triggerScenarios":"A workspace file upload through the runner API is attempted while process.platform is not \"darwin\" or \"linux\" — e.g. running the Paperclip server natively on Windows or FreeBSD, or inside an emulator reporting an exotic platform value.","commonSituations":"Development on Windows host without WSL; running the server in a FreeBSD/Alpine-musl container with an unusual platform string; deploying the native-runtime to an unsupported OS.","solutions":["Run the Paperclip server on Linux or macOS, where confined file opens are supported.","On Windows, use WSL2 (the process then reports linux) or a Linux container for the server.","Instead of a raw workspace path upload, attach the file as an authorized artifact reference, which is platform-independent.","If this is a legitimate deployment target, upstream platform support with an equivalent confined-open primitive before enabling workspace uploads there."],"exampleFix":"// before (unsupported)\n// server running on win32; openRunnerApiWorkspaceFile('C:\\\\workspace\\\\f.txt') throws\n// after\n// run server under WSL2/Linux and pass a POSIX absolute path, or upload via artifact reference\nawait openRunnerApiWorkspaceFile(\"/workspace/f.txt\"); // on linux","handlingStrategy":"validation","validationCode":"const SUPPORTED = new Set([\"darwin\", \"linux\"]);\nif (!SUPPORTED.has(process.platform)) {\n  throw new Error(`workspace uploads unsupported on ${process.platform}; use artifact references or run the server on Linux/macOS`);\n}","typeGuard":"function supportsConfinedOpens(p: NodeJS.Platform): boolean { return p === \"darwin\" || p === \"linux\"; }","tryCatchPattern":"try {\n  const handle = await openRunnerApiWorkspaceFile(path);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Workspace uploads require a platform\")) {\n    // fall back to uploading via an authorized artifact reference instead of a workspace path\n  } else throw err;\n}","preventionTips":["Deploy the Paperclip server only on Linux or macOS hosts (containers count as linux).","On Windows, run the server under WSL2 or a Linux container.","Prefer authorized artifact references for file uploads when portability matters.","Check process.platform at server startup and disable workspace-upload tools early with a clear message."],"tags":["platform","filesystem","security","native-runtime"],"backgroundTag":"unsupported-platform","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}