{"record":{"id":"2aa7421cb14d94d3","repo":"Foundry376/Mailspring","slug":"quick-preview-cannot-access-this-directory-file","errorCode":null,"errorMessage":"Quick preview cannot access this directory: ${filePath}","messagePattern":"Quick preview cannot access this directory: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/browser/quickpreview-ipc.ts","lineNumber":52,"sourceCode":"  // Only allow requests from the quickpreview renderer.html\n  if (!pathname.endsWith('/src/quickpreview/renderer.html')) {\n    throw new Error('Invalid IPC sender: request not from quickpreview renderer');\n  }\n};\n\n/**\n * Validate that a file path is within the allowed files directory.\n * Uses path.resolve() to prevent directory traversal attacks.\n */\nconst checkPathIsWithinFiles = (filePath: string): string => {\n  const baseDir = path.join(global.application.configDirPath, 'files');\n  const resolvedBase = path.resolve(baseDir);\n  const resolvedTarget = path.resolve(filePath);\n\n  // Ensure resolved path is within the allowed directory\n  // Append path.sep to prevent prefix-matching attacks (e.g., /files-evil/)\n  if (!resolvedTarget.startsWith(resolvedBase + path.sep)) {\n    throw new Error(`Quick preview cannot access this directory: ${filePath}`);\n  }\n\n  return resolvedTarget;\n};\n\nconst getFilePath = (url: string) => {\n  const { filePath } = JSON.parse(decodeURIComponent(new URL(url).search.slice(1)));\n  return checkPathIsWithinFiles(filePath);\n};\n\nconst previewFileAsString = (event: IpcMainInvokeEvent, { truncate } = { truncate: false }) => {\n  validateSender(event);\n  const filepath = getFilePath(event.sender.getURL());\n  let raw = fs.readFileSync(filepath).toString();\n  if (truncate) raw = raw.substr(0, 1000);\n  return raw;\n};\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/Foundry376/Mailspring/blob/648c685d602ece6bb00c22534b8734de6ac644b3/app/src/browser/quickpreview-ipc.ts#L34-L70","documentation":"Security guard in the quickpreview main-process IPC: after path.resolve on both sides, the requested file path does not lie under {configDirPath}/files, so the read is refused. This blocks directory-traversal payloads (e.g. ../../) from the quickpreview renderer reaching arbitrary files on disk.","triggerScenarios":"Thrown at app/src/browser/quickpreview-ipc.ts:52 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Regenerate the preview URL from the app itself — hand-edited or stale URLs with traversal sequences will be rejected by design","If legitimate previews fail, check that configDirPath hasn't changed (e.g. after a data directory migration)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"648c685d602ece6bb00c22534b8734de6ac644b3","analyzedAt":"2026-09-03T02:00:24.311Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}