payloadcms/payload · error · Forbidden

You are not allowed to perform this action.

Error message

You are not allowed to perform this action.

What it means

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.

Source

Thrown at packages/payload/src/uploads/checkFileAccess.ts:19

import type { Collection, TypeWithID } from '../collections/config/types.js'
import type { PayloadRequest, Where } from '../types/index.js'

import { executeAccess } from '../auth/executeAccess.js'
import { Forbidden } from '../errors/Forbidden.js'

export const checkFileAccess = async ({
  collection,
  filename,
  prefix,
  req,
}: {
  collection: Collection
  filename: string
  prefix?: string
  req: PayloadRequest
}): Promise<TypeWithID | undefined> => {
  if (filename.includes('../') || filename.includes('..\\')) {
    throw new Forbidden(req.t)
  }
  const { config } = collection

  const accessResult = await executeAccess(
    { slug: config.slug, data: { filename }, isReadingStaticFile: true, req },
    config.access.read,
  )

  const constraints: Where[] = []

  if (typeof accessResult === 'object') {
    constraints.push(accessResult)
  }

  if (typeof prefix === 'string') {
    constraints.push({ prefix: { equals: prefix } })
  }

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Do nothing client-side — the server correctly rejects this; ensure the route stays protected.
  2. Sanitize any filename your code derives from user input before constructing URLs.
  3. Log/monitor these requests as potential abuse.

Example fix

// before
const url = `/api/media/file/${userInput}` // userInput may contain ../

// after
const safe = userInput.replace(/\.\.[\\/]/g, '')
const url = `/api/media/file/${safe}`
Defensive patterns

Strategy: validation

Validate before calling

function sanitizeFilename(name: string): string {
  if (name.includes('../') || name.includes('..\\')) {
    throw new Error('Invalid filename: path traversal sequence')
  }
  return name.replace(/[^a-zA-Z0-9._-]/g, '_')
}

const url = `/api/media/file/${sanitizeFilename(userInput)}`

Type guard

function isSafeFilename(name: string): boolean {
  return !name.includes('../') && !name.includes('..\\')
}

if (!isSafeFilename(userInput)) throw new Error('unsafe filename')

Prevention

When it happens

Trigger: A request to a static upload URL whose filename segment contains `../` or `..\` — e.g. `/api/<collection>/file/../../etc/passwd` or a Windows-style `..\` escape.

Common situations: A malicious probe/scanner hitting upload endpoints; a misbehaving client constructing filenames from user input; SSRF-style traversal attempts against the static file server.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/df8a89d03fb0d0d6. Report an issue: GitHub.