{"record":{"id":"df8a89d03fb0d0d6","repo":"payloadcms/payload","slug":"you-are-not-allowed-to-perform-this-action-df8a89","errorCode":null,"errorMessage":"You are not allowed to perform this action.","messagePattern":"You are not allowed to perform this action\\.","errorType":"http","errorClass":"Forbidden","httpStatus":403,"severity":"error","filePath":"packages/payload/src/uploads/checkFileAccess.ts","lineNumber":19,"sourceCode":"import type { Collection, TypeWithID } from '../collections/config/types.js'\nimport type { PayloadRequest, Where } from '../types/index.js'\n\nimport { executeAccess } from '../auth/executeAccess.js'\nimport { Forbidden } from '../errors/Forbidden.js'\n\nexport const checkFileAccess = async ({\n  collection,\n  filename,\n  prefix,\n  req,\n}: {\n  collection: Collection\n  filename: string\n  prefix?: string\n  req: PayloadRequest\n}): Promise<TypeWithID | undefined> => {\n  if (filename.includes('../') || filename.includes('..\\\\')) {\n    throw new Forbidden(req.t)\n  }\n  const { config } = collection\n\n  const accessResult = await executeAccess(\n    { slug: config.slug, data: { filename }, isReadingStaticFile: true, req },\n    config.access.read,\n  )\n\n  const constraints: Where[] = []\n\n  if (typeof accessResult === 'object') {\n    constraints.push(accessResult)\n  }\n\n  if (typeof prefix === 'string') {\n    constraints.push({ prefix: { equals: prefix } })\n  }\n","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/checkFileAccess.ts#L1-L37","documentation":"Thrown by `checkFileAccess` as Forbidden when the requested filename contains a path-traversal sequence (`../` or `..\\`). This is a security guard that runs before any DB lookup or access-control evaluation, blocking attempts to escape the upload directory via the static-file route.","triggerScenarios":"A request to a static upload URL whose filename segment contains `../` or `..\\` — e.g. `/api/<collection>/file/../../etc/passwd` or a Windows-style `..\\` escape.","commonSituations":"A malicious probe/scanner hitting upload endpoints; a misbehaving client constructing filenames from user input; SSRF-style traversal attempts against the static file server.","solutions":["Do nothing client-side — the server correctly rejects this; ensure the route stays protected.","Sanitize any filename your code derives from user input before constructing URLs.","Log/monitor these requests as potential abuse."],"exampleFix":"// before\nconst url = `/api/media/file/${userInput}` // userInput may contain ../\n\n// after\nconst safe = userInput.replace(/\\.\\.[\\\\/]/g, '')\nconst url = `/api/media/file/${safe}`","handlingStrategy":"validation","validationCode":"function sanitizeFilename(name: string): string {\n  if (name.includes('../') || name.includes('..\\\\')) {\n    throw new Error('Invalid filename: path traversal sequence')\n  }\n  return name.replace(/[^a-zA-Z0-9._-]/g, '_')\n}\n\nconst url = `/api/media/file/${sanitizeFilename(userInput)}`","typeGuard":"function isSafeFilename(name: string): boolean {\n  return !name.includes('../') && !name.includes('..\\\\')\n}\n\nif (!isSafeFilename(userInput)) throw new Error('unsafe filename')","tryCatchPattern":null,"preventionTips":["Never construct upload URLs from raw user input; derive filenames from API docs.","Sanitize any client-derived filename by stripping traversal sequences.","Treat repeated traversal requests as abuse and rate-limit/log them."],"tags":["uploads","security","path-traversal","authorization"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}