{"record":{"id":"ed6fe2e26e43c322","repo":"CherryHQ/cherry-studio","slug":"invalid-mcp-package-upload-file-name-cannot-conta-ed6fe2","errorCode":null,"errorMessage":"Invalid MCP package upload: file name cannot contain path separators","messagePattern":"Invalid MCP package upload: file name cannot contain path separators","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/McpPackageService.ts","lineNumber":294,"sourceCode":"\nexport function validatePackageUploadPayload(\n  fileBuffer: ArrayBuffer | NodeJS.ArrayBufferView,\n  fileName: string,\n  packageFormat: McpPackageFormat\n): Buffer {\n  if (typeof fileName !== 'string') {\n    throw new Error('Invalid MCP package upload: file name must be a string')\n  }\n\n  const trimmedFileName = fileName.trim()\n  if (!trimmedFileName) {\n    throw new Error('Invalid MCP package upload: file name cannot be empty')\n  }\n  if (trimmedFileName !== fileName) {\n    throw new Error('Invalid MCP package upload: file name cannot contain leading or trailing whitespace')\n  }\n  if (trimmedFileName.includes('\\0') || /[/\\\\]/.test(trimmedFileName)) {\n    throw new Error('Invalid MCP package upload: file name cannot contain path separators')\n  }\n  if (!/^[A-Za-z0-9._ ()@+-]+$/.test(trimmedFileName)) {\n    throw new Error('Invalid MCP package upload: file name contains unsupported characters')\n  }\n  if (path.extname(trimmedFileName).toLowerCase() !== `.${packageFormat}`) {\n    throw new Error(`Invalid MCP package upload: expected a .${packageFormat} file`)\n  }\n\n  let buffer: Buffer\n  if (fileBuffer instanceof ArrayBuffer) {\n    buffer = Buffer.from(fileBuffer)\n  } else if (ArrayBuffer.isView(fileBuffer)) {\n    buffer = Buffer.from(fileBuffer.buffer, fileBuffer.byteOffset, fileBuffer.byteLength)\n  } else {\n    throw new Error('Invalid MCP package upload: file buffer must be an ArrayBuffer')\n  }\n\n  if (buffer.byteLength === 0) {","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/McpPackageService.ts#L276-L312","documentation":"Thrown by validatePackageUploadPayload when the trimmed filename contains a NUL byte or a forward/backward slash. The guard prevents the temp-file path (built as path.join(tempDir, `temp_file_${uuid}_${basename(fileName)}`)) from being influenced by separators in the renderer-supplied name. Although the code also runs path.basename on the name later, this check fails fast on any separator to give a clear message and to reject path-shaped input early.","triggerScenarios":"Renderer sent fileName containing \"/\", \"\\\", or \\0: e.g. \"subdir/pkg.mcpb\", \"C:\\\\Users\\\\x\\\\pkg.dxt\", or a name with an embedded control character. Often the result of passing a full file path instead of just the base name.","commonSituations":"The renderer sent file.path (the full filesystem path of the selected File) instead of file.name; on some platforms drag-and-drop handlers yield the absolute path; a test fixture used path.join to build the filename.","solutions":["On the renderer, send file.name (the base name) not file.path or any absolute path.","If you only have a path, call path.basename (or split on the OS separator) before sending, but prefer the File.name API.","Re-test the upload after the frontend change."],"exampleFix":"// renderer - before\nawait upload(fileBuffer, droppedItem.path)  // full path like /home/u/x.pkg\n// after\nawait upload(fileBuffer, droppedItem.name)  // base name only","handlingStrategy":"validation","validationCode":"function isBaseFileName(fileName: string): boolean {\n  return !fileName.includes('\\0') && !/[/\\\\]/.test(fileName)\n}","typeGuard":"function isBasenameOnly(s: unknown): s is string {\n  return typeof s === 'string' && !s.includes('\\0') && !/[/\\\\]/.test(s)\n}","tryCatchPattern":null,"preventionTips":["On the renderer, send File.name (the base name), never File.path or an absolute path.","If you only have a path, run path.basename before sending, but prefer File.name.","In drag-and-drop handlers, read the dropped item's name, not its full filesystem path."],"tags":["security","path-traversal","mcp","upload","validation","ipc"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}