payloadcms / payloadcms/payload

Image focal point update fails with GCP Storage and CSRF enabled

Open
#17,293 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area: core plugin: storage-* status: needs-triage v3
Dominant language
TypeScript
Stars
44.8k
Forks
4.2k
Avg merge
2d 21h
Merged PRs (30d)
53

Description

Describe the Bug

When attempting to change the focal point on an image on a gcsStorage-enabled collection with a CSRF protection enabled, the access.read hook lacks user information, which causes any authorisation checks fails.

Simple upload-enabled collection:

export const Media: CollectionConfig = {
  slug: 'media',
  access: {
    read: ({ req: { user } }) => {
      // Focal point update operation doesn't include the user in the request,
      // so any attempt to make a more complex access control check will fail.
      console.log('Media access control check: user is', user)
      return !!user
    },
    update: ({ req: { user } }) => {
      return !!user
    },
  },
  fields: [
    {
      name: 'alt',
      type: 'text',
    },
  ],
  upload: {
    mimeTypes: ['image/*'],
    adminThumbnail: 'thumbnail',
    focalPoint: true,
  },
}

Under described conditions, the req.user object in access.read will be NULL, when CSRF is enabled in Payload config.

Everything works as expected on a local storage, but fails on Google Cloud Storage:

  plugins: [
    gcsStorage({
      collections: {
        media: {
          prefix: 'media',
        },
      },
      bucket: 'YOUR-BUCKET.appspot.com',
      options: {},
    }),
  ],

The payload.config.ts has the CSRF set as:

  csrf: ['http://localhost:3000'],

Should this option be removed, everything works as expected.

This seems to be a regression, because it used to work, but at some point stopped working as expected, without any changes to CSRF options or cloud set up.

https://github.com/user-attachments/assets/f4f928cc-fc42-4634-ada5-74c8d69321c8

Link to the code that reproduces this issue

https://github.com/immotus/bug-upload-focal-point-update

Reproduction Steps
  1. Upload an image into the gcsStorage-enabled Media collection
  2. Edit focal point on the cloud-uploaded image
  3. Hit Save
  4. See the exception in the logs
  5. Comment out the following lines in payload.config.ts:
// serverURL: 'http://localhost:3000',
// csrf: ['http://localhost:3000'],
  1. Try to edit the focal point on the same image again — It will succeed as now req.user in access.read is not null.
Which area(s) are affected?

plugin: storage-*, area: core

Environment Info
Binaries:
  Node: 24.8.0
  npm: N/A
  Yarn: N/A
  pnpm: 10.17.0
Relevant Packages:
  payload: 3.86.0
  next: 16.2.6
  @payloadcms/db-mongodb: 3.86.0
  @payloadcms/graphql: 3.86.0
  @payloadcms/next/utilities: 3.86.0
  @payloadcms/plugin-cloud-storage: 3.86.0
  @payloadcms/richtext-lexical: 3.86.0
  @payloadcms/storage-gcs: 3.86.0
  @payloadcms/translations: 3.86.0
  @payloadcms/ui/shared: 3.86.0
  react: 19.2.6
  react-dom: 19.2.6
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 65399
  Available CPU cores: 16

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked reproduction and payload.config.ts, then reproduce the focal-point update with gcsStorage and CSRF enabled. Trace the focal-point request into the access.read hook and compare it with local storage; done means the cloud-backed update succeeds while access.read receives the authenticated user.

Written by the indexing model from the issue text.

Assessment

Tech stack
google-cloud, typescript
Domain
backend, cloud, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.