{"record":{"id":"1e931b64b28fcf15","repo":"toeverything/AFFiNE","slug":"refusing-to-read-mobile-payload-outside-cache-dir","errorCode":null,"errorMessage":"Refusing to read mobile payload outside cache dir: ${fileUrl}","messagePattern":"Refusing to read mobile payload outside cache dir: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/frontend/apps/mobile-shared/src/nbstore/payload.ts","lineNumber":55,"sourceCode":"  try {\n    decodedSegments = pathname\n      .split('/')\n      .filter(Boolean)\n      .map(segment => {\n        const decoded = decodeURIComponent(segment);\n        if (\n          !decoded ||\n          decoded === '.' ||\n          decoded === '..' ||\n          decoded.includes('/') ||\n          decoded.includes('\\\\')\n        ) {\n          throw new Error('path traversal');\n        }\n        return decoded;\n      });\n  } catch {\n    throw new Error(\n      `Refusing to read mobile payload outside cache dir: ${fileUrl}`\n    );\n  }\n\n  const fileName = decodedSegments.at(-1);\n  const bucket = decodedSegments.at(-2);\n  const cacheDir = decodedSegments.at(-3);\n  const parentDir = decodedSegments.at(-4);\n  const cacheParent = decodedSegments.at(-5);\n\n  if (\n    !fileName ||\n    !bucket ||\n    !cacheDir ||\n    !parentDir ||\n    cacheDir !== MOBILE_PAYLOAD_CACHE_DIR ||\n    !MOBILE_PAYLOAD_BUCKET_PATTERN.test(bucket) ||\n    !MOBILE_PAYLOAD_FILE_PATTERN.test(fileName) ||","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/frontend/apps/mobile-shared/src/nbstore/payload.ts#L37-L73","documentation":"Guard thrown when a pathname segment for a mobile payload file URL fails traversal validation: after decoding, a segment was empty, was '.' or '..', or contained a path separator (/ or \\), meaning the URL tries to escape the app's cache directory. This is a security sentinel preventing arbitrary file reads outside the sandbox.","triggerScenarios":"Thrown in assertMobileCachePath when path segments fail traversal checks (empty, dot, dotdot, separators) or when the path does not match the expected cache layout of nbstore-blob-cache under an allowed cache/tmp parent with hex bucket and .blob filename.","commonSituations":"Hit when a token points outside the app's sanctioned cache directories, e.g. tampered paths or wrong bucket/file naming. Treat it as a security guard; regenerate the payload rather than loosening the path.","solutions":["Only request payload files located inside the app cache directory.","Check the resolved path against the cache dir prefix before issuing the request; regenerate the token if it points elsewhere."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}