Skip to content

Update dependency @payloadcms/storage-s3 to v3.78.0 [SECURITY]#178

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-payloadcms-storage-s3-vulnerability
Open

Update dependency @payloadcms/storage-s3 to v3.78.0 [SECURITY]#178
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-payloadcms-storage-s3-vulnerability

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate Bot commented Apr 2, 2026

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
@payloadcms/storage-s3 (source) 3.68.23.78.0 age confidence

Payload has Insufficient Filename Validation in Client-Upload Signed-URL Endpoints

CVE-2026-34750 / GHSA-frq9-7j6g-v74x

More information

Details

Impact

The client-upload signed-URL endpoints for S3, GCS, Azure, and R2 did not properly sanitize filenames. An attacker could craft filenames to escape the intended storage location.

Consumers are affected if ALL of these are true:

  • Payload version < v3.78.0

  • Using client-upload signed-URL endpoints for any supported storage adapter

    Patches

This vulnerability has been patched in v3.78.0. Filename validation has been hardened for client uploads.

Consumers should upgrade to v3.78.0 or later.

Workarounds

Consumers can upgrade:

  • Limit access to client-upload signed-URL endpoints to trusted users only.

Severity

  • CVSS Score: 6.5 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

payloadcms/payload (@​payloadcms/storage-s3)

v3.78.0

Compare Source

🚀 Features

Feature Details

TypeScript Plugin for Component Paths - New @payloadcms/typescript-plugin validates PayloadComponent import paths directly in your IDE. It checks that referenced files and exports exist, provides autocomplete for file paths and export names, supports go-to-definition on component path strings, and understands all Payload path conventions including absolute paths, relative paths, tsconfig aliases, and package imports. #​15779

screenshot.2026-02-26.at.15.55.40.mp4
pnpm add -D @&#8203;payloadcms/typescript-plugin
{
  "compilerOptions": {
    "plugins": [{ "name": "next" }, { "name": "@&#8203;payloadcms/typescript-plugin" }]
  }
}

Trash Out of Beta with Granular Delete Access - Trash is now a stable feature. Delete access control can now distinguish between trashing and permanently deleting — allowing you to permit users to soft-delete documents while restricting permanent deletion to admins. When data.deletedAt is being set, the operation is a trash; otherwise it's a permanent delete. #​15210

import type { CollectionConfig } from 'payload'

export const Posts: CollectionConfig = {
  slug: 'posts',
  trash: true,
  access: {
    delete: ({ req: { user }, data }) => {
      // Not logged in - no access
      if (!user) {
        return false
      }

      // Admins can do anything (trash or permanently delete)
      if (user.roles?.includes('admin')) {
        return true
      }

      // Regular users: check what operation they're attempting
      // If data.deletedAt is being set, it's a trash operation - allow it
      if (data?.deletedAt) {
        return true
      }

      // Otherwise it's a permanent delete - deny for non-admins
      return false
    },
  },
  fields: [
    // ...
  ],
}

Widget Fields (next, ui) - Dashboard widgets can now declare configurable fields, similar to Blocks. Widget data is editable from a new drawer UI when in dashboard editing mode. Full type generation is included — WidgetInstance<T> is generic with typed data and width, and WidgetServerProps is generic so widget components receive typed widgetData. #​15700

Screen.Recording.2026-02-23.at.16.25.40.mov
import { buildConfig } from 'payload'

export default buildConfig({
  admin: {
    dashboard: {
      widgets: [
        {
          slug: 'sales-summary',
          ComponentPath: './components/SalesSummary.tsx#default',
          fields: [
            { name: 'title', type: 'text' },
            {
              name: 'timeframe',
              type: 'select',
              options: ['daily', 'weekly', 'monthly', 'yearly'],
            },
            { name: 'showTrend', type: 'checkbox' },
          ],
          minWidth: 'small',
          maxWidth: 'medium',
        },
      ],
    },
  },
})
import type { WidgetServerProps } from 'payload'

import type { SalesSummaryWidget } from '../payload-types'

export default async function SalesSummaryWidgetComponent({
  widgetData,
}: WidgetServerProps<SalesSummaryWidget>) {
  const title = widgetData?.title ?? 'Sales Summary'
  const timeframe = widgetData?.timeframe ?? 'monthly'

  return (
    <div className="card">
      <h3>
        {title} ({timeframe})
      </h3>
    </div>
  )
}

MCP Plugin Out of Beta (plugin-mcp) - @payloadcms/plugin-mcp is now stable and ready for production use. #​15711

Virtual Field Filtering in MCP (plugin-mcp) - Virtual fields (virtual: true) are now automatically stripped from MCP tool input schemas and filtered from parsed data before create, update, and updateGlobal operations. This prevents non-stored fields from appearing as accepted MCP parameters. #​15680

Markdown Transformer for Upload Nodes (richtext-lexical) - Upload nodes are now properly converted when using convertLexicalToMarkdown. Previously, upload nodes were silently dropped during markdown conversion. Now populated image uploads output ![alt text](/uploads/image.jpg), non-image uploads output link syntax, and non-populated uploads output a reference placeholder so data is never lost. #​15630

Dashed Button Style (ui) - Adds a new dashed button style variant. Also replaces box-shadow with border on all buttons and fixes icon-only button padding. #​15728

Button styles overview

Editable Query Presets from Form View (ui) - Query presets can now be created and edited directly from the document form view using a full WhereBuilder, column picker, and groupBy selector — no longer requiring the list view to build queries first. #​15657

Screen.Recording.2026-02-17.at.18.15.34.mov

🐛 Bug Fixes
  • getFieldsToSign crashes when user missing group/tab fields (#​15775) (9f0c101)
  • improve mobile touch support for dnd (#​15771) (418bb92)
  • prevent silent data overwrites on concurrent edits (#​15749) (7a3f43f)
  • preserve block metadata in mergeLocalizedData and filterDataToSelectedLocales (#​15715) (6557292)
  • return 400 for malformed JSON request bodies (#​15706) (4861fa1)
  • globals not updating updatedAt when saving drafts (#​15764) (df17cb1)
  • return early if pasteURL is not defined (#​15748) (23d52a0)
  • prevent req.file leak between sequential duplicate() calls on upload collections (#​15620) (2baea2e)
  • sanitize filenames in storage adapters (#​15746) (45bd2f1)
  • throw error for unknown query operators (#​15739) (08226db)
  • preserve locale data in unnamed groups with localizeStatus (#​15658) (38b8c68)
  • next: conditionally query snapshot field based on localization (#​15693) (d5706ee)
  • plugin-import-export: update docs on jobs and basic usage as well as visibility (#​15695) (a40210c)
  • plugin-mcp: use inline block schemas in JSON output (#​15675) (a66e844)
  • plugin-multi-tenant: hasMany tenant fields double-wrap arrays in filterOptions (#​15709) (aaddeac)
  • plugin-multi-tenant: return false instead of query when no tenants (#​15679) (f5a5bd8)
  • richtext-lexical: bump acorn to resolve type mismatch with transitive dep (#​15791) (801e851)
  • richtext-lexical: link markdown regex should not match similar looking image markdown (#​15713) (0a0afb0)
  • richtext-lexical: use headingLevel in danish heading label (#​15685) (ad4c0f6)
  • richtext-lexical: strip server-only properties from blocks in lexical client schema map (#​15756) (c05ace2)
  • templates: ecommerce find my order access functionality to use email (#​15736) (b317eaa)
  • ui: array field add button margin not applying consistently (#​15773) (ee298f5)
  • ui: respect custom Cell components on richText fields in list view (#​15762) (139cf3e)
  • ui: use correct translation key for collection version restore modal (#​15757) (c1892eb)
  • ui: encode HTML special characters in version diff view (#​15747) (30fee83)
  • ui: flash of border on list selection buttons (#​15735) (7f3c6c8)
🛠 Refactors
🎨 Styles
  • richtext-lexical: lists and quotes have inconsistent letter spacing (#​15682) (f2397a8)
🧪 Tests
📝 Templates
  • fix cloudflare logger error in with-cloudflare-d1 template (#​15752) (8791a72)
  • ecommerce add missing access control on collections (#​15744) (c74d91d)
  • fix ecommerce webhooks url and update docs on using stripe webhooks (#​15681) (677596c)
🏡 Chores
🤝 Contributors

v3.77.0

Compare Source

🚀 Features

Feature Details

Local API Depth Consistency - The depth option passed to Local API calls like payload.find() is now automatically set on req.query.depth. Previously, hooks relying on req.query.depth would behave differently between Local API and REST/GraphQL calls unless you manually passed req: { query: { depth: x } } in addition to depth: x. This change ensures consistent behavior across all API methods. #​15023

Custom ID Support in db.create (db-*) - New customID argument on payload.db.create allows creating documents with a specific ID without requiring a custom ID field in your collection schema. #​15653

payload.db.create({ collection: 'posts', customID: 'ce98d6c4-c3ab-45de-9dfc-bf33d94cc941', data: { } })

MCP Plugin Migration (plugin-mcp) - Migrates from the deprecated @vercel/mcp-adapter to mcp-handler and bumps @modelcontextprotocol/sdk to 1.25.2 addressing a security vulnerability. Exposes new handler options: disableSse, onEvent, and redisUrl. #​15661

import { mcpPlugin } from '@&#8203;payloadcms/plugin-mcp'

export default buildConfig({
  plugins: [
    mcpPlugin({
      // Optional: Enable SSE transport (disabled by default)
      disableSse: false,
      // Optional: Redis URL for SSE session management (defaults to REDIS_URL env)
      redisUrl: 'redis://localhost:6379',
      // Optional: Track MCP events for analytics/debugging
      onEvent: (event) => {
        console.log('MCP event:', event)
      },
    }),
  ],
})

🐛 Bug Fixes
  • hasMany text fields cannot be filtered with contains operator (#​15671) (4513a05)
  • use consistent empty state styling between list and folder views (#​15555) (8953b37)
  • populate previousValue correctly in afterChange hooks for nested lexical fields (#​15623) (1cc3bb9)
  • add i18n support for dashboard edit mode buttons (#​15564) (818e31d)
  • next: handle undefined fieldTab in version diff tabs (#​15590) (bbacab8)
  • plugin-cloud-storage: ensure file data persists across operations (#​15570) (6af3673)
  • plugin-cloud-storage: generateFileURL only ran when disablePayloadAccessControl was true (#​15667) (6c5611c)
  • plugin-import-export: remove deprecated import (#​15666) (733b1df)
  • plugin-import-export: export and import issues when using custom IDs (#​15518) (7e2a3ab)
  • plugin-import-export: columns being duplicated when using toCSV hook (#​15597) (28e07dc)
  • plugin-mcp: resolve union type fields failing in update tool (#​15660) (9ae89dd)
  • plugin-multi-tenant: improve translation for "Tenant" (use "Mandant" instead of "Mieter") (#​15537) (4d4033b)
  • plugin-multi-tenant: tenant selector not appearing after login (#​15617) (dd09f67)
  • storage-r2: build error due to types issue in R2 Bucket type (#​15670) (7d1e233)
  • ui: fix broken polymorphic join edit drawer (#​15621) (d450e99)
📚 Documentation
🧪 Tests
🏡 Chores
🤝 Contributors

v3.76.1

Compare Source

🐛 Bug Fixes
  • use optional chaining for adminThumbnail size lookup to prevent crash (#​15586) (6937eec)
  • non-image files should not recieve 0 bytes with useTempFiles (#​15538) (a313627)
  • add CSP headers to SVG uploads to prevent XSS (#​15506) (8283c25)
  • richtext-lexical: link tooltip overflows outside viewport with long URLs (#​15584) (af6b1a1)
  • ui: prevent Tabs field crash when stored tabIndex exceeds tab count (#​15588) (a9e296e)
  • ui: copy to locale function swallowing errors (#​15562) (8ce62d8)
  • ui: ensure unpublish button only shows when drafts are enabled (#​15459) (69dc5e6)
⚙️ CI

v3.76.0

Compare Source

🚀 Features
  • plugin-import-export: adds new exportLimit, importLimit and per collection limit control (#​15405) (a7beeca)
🐛 Bug Fixes
  • drizzle: use dynamic import for typescript to avoid dependency in production (#​15545) (98a756c)
  • live-preview-vue: update build config to compile as esm (#​14293) (60c65ed)
  • next: drop support for Next.js versions with known CVEs, add canary 16.2.0 support (#​15547) (2b3061a)
  • next: suppress webpack "Critical dependency" warning in dynamicImport (#​15534) (6158489)
  • plugin-import-export: errors when import/export files were stored in a storage adapter such as S3 (#​15441) (73a9650)
  • ui: tab error badge not counting required array validation errors (#​15563) (0ce6193)
  • ui: folder view toggle button styles overridden due to equal specificity (#​15544) (df42bec)
  • ui: remove clearData call in dropzone drop handler (#​10475) (b4e6761)
📝 Templates
⚙️ CI
🏡 Chores
  • fix deprecation warning when running reinstall or clean:all monorepo script (#​15535) (03bfaf4)
  • drizzle: add logs indicating which migration statements are generated (#​15374) (306974d)
🤝 Contributors

v3.75.0

Compare Source

🚀 Features
  • adds beforeNav and afterNav component slots (#​15493) (f23a1df)
  • next: pass full initReq context to server functions and dashboard widgets (#​15427) (ce13e97)
🐛 Bug Fixes
  • handle absolute paths correctly with tempFileDir upload option (#​14436) (5ca9bd4)
  • ungenerated image sizes should not store original URL (#​15454) (fa1cd62)
  • add safety check to redirects from external file URL uploads (#​15458) (1041bb6)
  • sass warning not hidden during webpack build (#​15442) (dec0ea7)
  • add collection property to auth documents, fixing multi tenancy access control issue (#​15404) (d6aa6cc)
  • graphql: blocks return null with select: true (#​15464) (c2baef4)
  • next: versions diff error when swapping blocks with relationship fields (#​15478) (5ba0055)
  • next: export SlugField from the client dir not rsc (#​15461) (6c07f3b)
  • next: sync modular dashboard widgets when server component re-renders (#​15439) (5495b47)
  • plugin-ecommerce: variant creation blocked by variants in trash (#​15449) (3f01682)
  • plugin-mcp: create and update resource tools now support point fields (#​15381) (a28261d)
  • ui: extra padding rendering in list view when no description exists (#​15507) (3ff6be4)
  • ui: remove slug field from rsc exports (#​15480) (8f66035)
⚡ Performance
  • next: avoid re-calculating permissions in some server functions, pass missing args (#​15428) (9c8be5c)
📚 Documentation
🎨 Styles
🧪 Tests
⚙️ CI
🏡 Chores
🤝 Contributors

v3.74.0

Compare Source

🚀 Features

Override Access in Document-Level Hooks - Access the overrideAccess value inside collection and global hooks. Useful when hook logic needs to know whether access control was bypassed, such as when querying related documents up a hierarchy. #​15421

export const Posts: CollectionConfig = {
  slug: 'posts',
  hooks: {
    beforeChange: [
      ({ overrideAccess, req }) => {
        if (overrideAccess) {
          // Access control was bypassed
        }
      },
    ],
  },
}

Extended strictDraftTypes to All Operations - When strictDraftTypes: true is enabled, TypeScript now enforces draft type safety across all Local API operations (not just queries). The draft option is forbidden for collections/globals without drafts enabled, preventing silent runtime behavior where draft flags are ignored. #​15292

import { buildConfig } from 'payload'

export default buildConfig({
  typescript: {
    strictDraftTypes: true, // Enables compile-time draft enforcement
  },
  // ...
})

⚠️ Note: Generic collection slugs may require explicit type assertions when using draft options.


Custom UnpublishButton Component - Customize the UnpublishButton in collection and global configs, following the same pattern as PublishButton and SaveButton. Previously hardcoded. #​15400

export const Posts: CollectionConfig = {
  slug: 'posts',
  admin: {
    components: {
      edit: {
        UnpublishButton: '/components/CustomUnpublishButton',
      },
    },
  },
}

R2 Multipart Client Uploads (storage-r2) - Upload large files directly from the client using R2's multipart API. Files are split into smaller parts and uploaded separately, avoiding Cloudflare Worker memory limits. #​14733


Popup Prevent Close Attribute (ui) - Add interactive elements inside popups without triggering close behavior by adding the data-popup-prevent-close attribute. #​15407

<Popup>
  <button data-popup-prevent-close onClick={handleClick}>
    Click me without closing
  </button>
</Popup>

Popup Portal className (ui) - Customize the Popup component's portal container with the new portalClassName prop. #​15406

<Popup portalClassName="my-custom-portal-class">
  {/* content */}
</Popup>
🐛 Bug Fixes
  • isolate payload-preferences by auth collection (#​15425) (2dc2e7c)
  • traverseFields returning wrong parentPath dot notation for non-localised tabs (#​15394) (99b051e)
  • widgets and other features failing with transitive dependency imports (#​15392) (5561799)
  • replace deprecated scmp with crypto.timingSafeEqual (#​15322) (2511c02)
  • find afterRead hooks should behave like findByID (#​15357) (3e27155)
  • remove depth from count operation types (#​15356) (dfc1600)
  • publish button incorrectly shown after saving draft when access denied (#​15319) (e833fe6)
  • next: version view throws useLocale() server error (#​15380) (2ce26fa)
  • next: ensure query preset from url is applied (#​15323) (592f404)
  • next: ensure save preset button is not shown when there are no changes (#​15320) (e9af097)
  • plugin-cloud-storage: prevent infinite loop when cropping media (#​15393) (345a9c7)
  • plugin-cloud-storage: adds beforeChange hook to generate url on create (#​15401) (d269d39)
  • richtext-slate: localized indicator not displaying in label (#​15412) (126f713)
  • ui: use the formatAdminUrl function to generate unpublish url (#​15375) (453e8a6)
  • ui: restore default columns after clearing query preset (#​15360) (029699d)
  • ui: prevent globals crash with arrays fields when lock state user is undefined in handleDocumentLocking (#​15259) (ea76ca0)
  • ui: getEntityConfig did not respect globalSlug if collectionSlug is undefined (#​15362) (b54059c)
📚 Documentation
  • clarify beforeValidate and beforeChange hook data behavior (#​15300) (ba9605e)
  • add payload.logger.error usage guidelines to CLAUDE.md (#​15398) (cdbfda2)
  • updated redirects plugin integration docs and postgres connection troubleshooting (#​15383) (9b2221e)
  • improve select jsdocs and empty select docs (#​15336) (4181a12)
🧪 Tests
  • make integration tests for the fields and select suites faster (#​15434) (26ba779)
📝 Templates
🔨 Build
⚙️ CI
🏡 Chores
🤝 Contributors

Note

PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • ""
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants