CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-93363

CVE-2026-93363: Improper Access Control in Payload CMS Storage Upload Route

Alon Barad
Alon Barad
Software Engineer

Nov 4, 2026·9 min read·3 visits

Executive Summary (TL;DR)

Authenticated low-privileged users can bypass collection-level access controls in Payload CMS (versions 3.25.0 to < 3.90.0 and 4.0.0-canary.0 to < 4.0.0-canary.34) by directly querying `/api/upload-instructions` when using third-party storage adapters like `@payloadcms/storage-vercel-blob`, or by injecting `overrideAccess: true` into the JSON request body.

Payload CMS contains a missing authorization vulnerability (CWE-862) in its client-side upload instructions endpoint and the `@payloadcms/storage-vercel-blob` storage adapter. Two distinct logic defects allow authenticated users lacking collection-level `create` or `update` permissions to generate signed upload tokens and upload arbitrary files directly to external cloud storage.

Vulnerability Overview

Payload CMS is an open-source, headless content management system and application framework built with TypeScript and Node.js. It provides extensible file management capabilities through dedicated upload collections and pluggable cloud storage adapters, such as @payloadcms/storage-vercel-blob and @payloadcms/storage-r2. To reduce server bandwidth overhead when handling large media assets, Payload supports client-side direct uploads, where the browser requests a pre-signed upload URL or client token from the CMS and transmits file bytes directly to the cloud storage provider.

In Payload CMS versions 3.25.0 prior to 3.90.0 and 4.0.0-canary.0 prior to 4.0.0-canary.34, the server-side endpoint responsible for issuing these client upload credentials (/upload-instructions) fails to enforce collection-level authorization properly. Tracked as CVE-2026-93363 (and GHSA-mc8m-rr6c-r5qr), this vulnerability is classified under CWE-862 (Missing Authorization).

The flaw stems from two independent implementation defects in packages/payload/src/uploads/endpoints/uploadInstructions.ts. First, the authorization routine was conditionally gated behind a boolean check that skipped permission evaluation whenever a custom storage adapter was configured. Second, the HTTP endpoint handler passed the unsanitized client JSON body into the internal instruction generator via object spreading, allowing callers to supply internal API flags such as overrideAccess: true.

As a result, any low-privileged authenticated user can request valid upload instructions and pre-signed tokens for restricted upload collections. The user can then upload unauthorized files directly into the underlying cloud storage bucket without possessing create or update privileges on the target collection.

Root Cause Analysis

The root cause of CVE-2026-93363 resides in how Payload CMS processes requests to the /upload-instructions endpoint within packages/payload/src/uploads/endpoints/uploadInstructions.ts. In Payload's architecture, internal Local API operations accept an overrideAccess boolean parameter. When overrideAccess is set to true (the default for internal server-to-server calls), Payload bypasses access control functions; when invoked via HTTP REST or GraphQL endpoints, overrideAccess is supposed to be enforced as false so that collection-level permissions are evaluated against the requesting user session (req.user).

The first defect is a conditional authorization bypass triggered by the presence of a third-party storage adapter. When a collection is configured to use a storage plugin that supports client uploads (such as @payloadcms/storage-vercel-blob), the collection registers an uploadInstructions handler object. In getUploadInstructions, the access control check was written with the condition if (!uploadInstructions && !overrideAccess). Because uploadInstructions is defined and truthy when a storage adapter is active, !uploadInstructions evaluates to false. Consequently, the entire permission validation block is skipped, and execution immediately delegates token generation to uploadInstructions.generate().

The second defect is a mass assignment / internal parameter injection flaw in uploadInstructionsEndpoint. The endpoint handler parsed the incoming HTTP request JSON body into the upload variable and passed it directly into getUploadInstructions({ ...upload, req }) using the JavaScript spread operator (...).

Because the getUploadInstructions function signature accepts overrideAccess as a property of its first argument object (defaulting to false only if undefined), spreading the raw client JSON object allowed an attacker to include "overrideAccess": true in the HTTP request body. This explicitly overwrote the default overrideAccess = false parameter, disabling access control checks even for standard staged uploads that did not use a custom storage adapter.

Code Analysis

Examining the vulnerable implementation in packages/payload/src/uploads/endpoints/uploadInstructions.ts prior to commit 47abe9bb5c444330dbfaa9a5bc2033337932270b illustrates how both defects interact within the same file.

// VULNERABLE CODE: packages/payload/src/uploads/endpoints/uploadInstructions.ts
export async function getUploadInstructions({
  overrideAccess = false,
  req,
  ...upload
}: UploadInstructionsArgs): Promise<Response> {
  const uploadInstructions = req.payload.collections[upload.collectionSlug]?.config.upload?.adapter
 
  // Defect 1: If an adapter is present (uploadInstructions is truthy),
  // this entire authorization block is skipped.
  if (!uploadInstructions && !overrideAccess) {
    if (!req.user) {
      throw new Forbidden(req.t)
    }
 
    const collectionPermissions = (await getAccessResults({ req })).collections?.[
      upload.collectionSlug
    ]
 
    if (!collectionPermissions?.create && !collectionPermissions?.update) {
      throw new Forbidden(req.t)
    }
  }
 
  return uploadInstructions
    ? uploadInstructions.generate({ ...upload, overrideAccess, req })
    : generateStagedUploadInstructions({ ...upload, req })
}
 
export const uploadInstructionsEndpoint: Endpoint = {
  handler: async (req) => {
    const upload = (await req.json!()) as UploadInstructionsRequest
    if (!upload) {
      throw new APIError('Invalid upload instructions request', 400)
    }
 
    // Defect 2: Object spread (...upload) allows client JSON to inject overrideAccess: true
    return Response.json(await getUploadInstructions({ ...upload, req }))
  },
  method: 'post',
  path: '/upload-instructions',
}

In commit 47abe9bb5c444330dbfaa9a5bc2033337932270b, the maintainers resolved the vulnerability through three structural changes. First, they created a dedicated authorization helper function, assertClientUploadAccess, in packages/payload/src/uploads/assertClientUploadAccess.ts. Rather than computing global access results across all collections via getAccessResults, this helper directly evaluates the target collection's create and update access control functions using executeAccess:

// PATCHED HELPER: packages/payload/src/uploads/assertClientUploadAccess.ts
export const assertClientUploadAccess = async ({
  collectionSlug,
  req,
}: {
  collectionSlug: string
  req: PayloadRequest
}): Promise<void> => {
  if (!req.user) {
    throw new Forbidden(req.t)
  }
 
  const collectionConfig = req.payload.collections[collectionSlug]?.config
 
  if (!collectionConfig) {
    throw new Forbidden(req.t)
  }
 
  // Evaluate collection-level create access first
  const canCreate = await executeAccess(
    { slug: collectionSlug, disableErrors: true, req },
    collectionConfig.access.create,
  )
 
  if (canCreate) {
    return
  }
 
  // Fall back to evaluating update access if create is denied
  const canUpdate = await executeAccess(
    { slug: collectionSlug, disableErrors: true, req },
    collectionConfig.access.update,
  )
 
  if (!canUpdate) {
    throw new Forbidden(req.t)
  }
}

Second, getUploadInstructions was updated to call assertClientUploadAccess unconditionally whenever overrideAccess is false, prior to invoking either custom storage adapter handlers or staged upload handlers. Third, uploadInstructionsEndpoint was refactored to explicitly pick only the expected properties from the client payload, preventing parameter injection:

// PATCHED ENDPOINT: packages/payload/src/uploads/endpoints/uploadInstructions.ts
export async function getUploadInstructions({
  overrideAccess = false,
  req,
  ...upload
}: UploadInstructionsArgs): Promise<Response> {
  // Fix 1: Unconditionally enforce access checks regardless of storage adapter presence
  if (!overrideAccess) {
    await assertClientUploadAccess({ collectionSlug: upload.collectionSlug, req })
  }
 
  const uploadInstructions = req.payload.collections[upload.collectionSlug]?.config.upload?.adapter
  return uploadInstructions
    ? uploadInstructions.generate({ ...upload, overrideAccess, req })
    : generateStagedUploadInstructions({ ...upload, req })
}
 
export const uploadInstructionsEndpoint: Endpoint = {
  handler: async (req) => {
    const upload = (await req.json!()) as UploadInstructionsRequest
    if (!upload) {
      throw new APIError('Invalid upload instructions request', 400)
    }
 
    // Fix 2: Explicit property mapping prevents client injection of overrideAccess
    return Response.json(
      await getUploadInstructions({
        collectionSlug: upload.collectionSlug,
        docPrefix: upload.docPrefix,
        filename: upload.filename,
        filesize: upload.filesize,
        mimeType: upload.mimeType,
        req,
      }),
    )
  },
  method: 'post',
  path: '/upload-instructions',
}

> [!NOTE] > Fix Completeness Assessment: In addition to patching /upload-instructions, commit 47abe9bb5c444330dbfaa9a5bc2033337932270b also audited and updated multipart upload handlers in other storage adapters (such as @payloadcms/storage-r2) to invoke assertClientUploadAccess({ collectionSlug, req }). This ensures consistent access enforcement across both single-request signed URLs and multipart upload initiation endpoints.

Exploitation

Exploiting CVE-2026-93363 requires network access to the Payload CMS HTTP API and normally requires a valid authentication session (PR:L) for a low-privileged user account (such as a standard registered user or viewer role) that lacks create and update permissions on a target upload collection. However, if an attacker exploits the overrideAccess: true parameter injection vector, the !req.user check inside the vulnerable conditional block is also bypassed.

To execute the attack against an application using @payloadcms/storage-vercel-blob or a similar client-upload configuration, the attacker first identifies the slug of an upload-enabled collection (for example, media or restricted-documents). The attacker then sends a crafted POST request to the /api/upload-instructions endpoint.

POST /api/upload-instructions HTTP/1.1
Host: target.example.com
Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
 
{
  "collectionSlug": "restricted-documents",
  "filename": "unauthorized-asset.pdf",
  "filesize": 204800,
  "mimeType": "application/pdf",
  "overrideAccess": true
}

When the vulnerable server receives this request, uploadInstructionsEndpoint spreads the JSON properties into getUploadInstructions. Because uploadInstructions is defined on the restricted-documents collection (and overrideAccess is injected as true), the server skips all role and permission checks.

The server subsequently invokes the storage adapter's generate function, which communicates with the cloud provider (or signs a token locally using BLOB_READ_WRITE_TOKEN) and returns the upload instructions and signed token in the HTTP response. The attacker uses the returned credentials to upload the file payload directly to the Vercel Blob store or configured cloud bucket.

Impact Assessment

The primary security impact of CVE-2026-93363 is a partial loss of integrity (I:L in CVSS v3.1, VI:L in CVSS v4.0) on the affected system's storage layer. Attackers cannot read existing sensitive files (C:N) or directly delete existing database records (A:N) through this vector alone, resulting in a CVSS v3.1 base score of 4.3 (Medium) and a CVSS v4.0 base score of 5.3 (Medium).

By bypassing collection-level access controls on upload routes, an unauthorized user can persist arbitrary files inside the application's configured cloud storage bucket (such as Vercel Blob or Cloudflare R2). Depending on how the downstream application serves or processes files from the storage bucket, this enables several secondary risks:

  • Storage Quota and Financial Exhaustion: Attackers can repeatedly request upload tokens for large files and push data directly to the cloud storage provider, driving up bandwidth and storage costs.
  • Hosting of Unauthorized Content: If the cloud bucket is configured for public read access, attackers can abuse the trusted domain of the organization's blob storage to host phishing pages, malware payloads, or unapproved media.
  • Asset Overwrite / Prefix Collision: If the storage adapter configuration does not enforce unique randomized prefixes or allows predictable docPrefix values, an attacker could overwrite existing objects in the blob store.

According to FIRST EPSS telemetry, CVE-2026-93363 currently holds an EPSS score of 0.00177 (0.18%), placing it in the 7.28th percentile. It is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog, and no active in-the-wild exploitation campaigns have been recorded.

Remediation

To remediate CVE-2026-93363, operators must upgrade payload and all installed @payloadcms/storage-* packages (including @payloadcms/storage-vercel-blob and @payloadcms/storage-r2) to a patched release. The vulnerability is fixed in Payload 3.90.0 for the 3.x release line and Payload 4.0.0-canary.34 for the 4.x canary line.

# Using pnpm
pnpm update payload @payloadcms/storage-vercel-blob
 
# Using npm
npm update payload @payloadcms/storage-vercel-blob

For environments where an immediate version upgrade is not feasible, developers can implement two workarounds to mitigate the exposure. First, if using @payloadcms/storage-vercel-blob with clientUploads enabled, explicitly define an access callback inside the clientUploads configuration object to enforce user role checks inside the adapter itself:

import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob'
 
vercelBlobStorage({
  collections: {
    media: true,
  },
  clientUploads: {
    // Explicitly enforce authorization at the adapter level
    access: ({ collectionSlug, req }) => {
      return Boolean(req.user && req.user.roles?.includes('admin'))
    },
  },
  token: process.env.BLOB_READ_WRITE_TOKEN,
})

Second, deploy Web Application Firewall (WAF) or reverse proxy rules at the ingress layer to inspect POST requests targeting /api/upload-instructions. Any request body containing the JSON key overrideAccess should be blocked immediately, as legitimate client upload requests never include internal Local API control flags.

Official Patches

Payload CMSOfficial Fix Commit (47abe9bb5c444330dbfaa9a5bc2033337932270b)
Payload CMSPayload CMS v3.90.0 Release
Payload CMSGitHub Security Advisory (GHSA-mc8m-rr6c-r5qr)

Fix Analysis (1)

Technical Appendix

CVSS Score
4.3/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
EPSS Probability
0.18%
Top 93% most exploited

Affected Systems

Payload CMS (`payload`)Payload CMS Vercel Blob Storage Adapter (`@payloadcms/storage-vercel-blob`)Payload CMS Cloudflare R2 Storage Adapter (`@payloadcms/storage-r2`)

Affected Versions Detail

Product
Affected Versions
Fixed Version
payload / @payloadcms/storage-vercel-blob
payloadcms
>= 3.25.0, < 3.90.03.90.0
payload / @payloadcms/storage-vercel-blob
payloadcms
>= 4.0.0-canary.0, < 4.0.0-canary.344.0.0-canary.34
AttributeDetail
Vulnerability TypeMissing Authorization (CWE-862)
CVSS v3.1 Score4.3 Medium (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N)
CVSS v4.0 Score5.3 Medium (CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N)
EPSS Score0.18% (7.28th percentile)
Attack VectorNetwork via POST /api/upload-instructions
Affected Versions3.25.0 to < 3.90.0; 4.0.0-canary.0 to < 4.0.0-canary.34
Patched Versions3.90.0, 4.0.0-canary.34
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1068Exploitation for Privilege Escalation
Privilege Escalation
CWE-862
Missing Authorization

The product does not perform an authorization check when an actor attempts to access a resource or perform an action.

Vulnerability Timeline

Vulnerability patched upstream in commit 47abe9bb5c444330dbfaa9a5bc2033337932270b and released in Payload v3.90.0
2026-03-01

References & Sources

  • [1]CVE-2026-93363 Record (CVE.org)
  • [2]NVD - CVE-2026-93363
  • [3]GitHub Security Advisory GHSA-mc8m-rr6c-r5qr
  • [4]VulnCheck Security Advisory: Payload CMS @payloadcms/storage-vercel-blob Improper Access Control
  • [5]Payload CMS Fix Commit 47abe9bb5c444330dbfaa9a5bc2033337932270b
  • [6]Payload CMS Release v3.90.0
  • [7]Payload CMS GitHub Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 3 hours ago•CVE-2026-55098
6.5

CVE-2026-55098: Cross-Database Authorization Bypass via DuckDB Table-Valued I/O Functions in Basekick-Labs Arc

CVE-2026-55098 (GHSA-93cm-2v4m-c56c) is an authorization bypass and sensitive information disclosure vulnerability in Basekick-Labs Arc prior to version 26.06.2. The flaw stems from an incomplete remediation of CVE-2026-47735, which failed to restrict the full suite of DuckDB table-valued filesystem I/O functions and quoted-identifier invocations. Because Arc's query parser ignores function calls during table reference extraction, authenticated users with minimal or empty permissions can invoke functions like parquet_scan(), glob(), and read_blob() to read, enumerate, and extract telemetry data across all tenant databases residing within the shared local storage root.

Alon Barad
Alon Barad
4 views•10 min read
•about 4 hours ago•CVE-2026-113787
6.1

CVE-2026-113787: Stored Cross-Site Scripting via Unescaped Style Attributes in odf-kit

CVE-2026-113787 is a stored Cross-Site Scripting (XSS) and HTML injection vulnerability affecting the odf-kit npm package from version 0.6.0 prior to 0.14.2. The HTML conversion engines (odtToHtml and odsToHtml) interpolate document-controlled styling and image attributes directly into inline style and src attributes without escaping double-quote characters. A remote attacker can supply a crafted .odt or .ods document to break out of HTML attribute boundaries and execute arbitrary JavaScript in the context of any web application rendering the converted HTML.

Alon Barad
Alon Barad
4 views•11 min read
•about 18 hours ago•GHSA-M3QR-FVP4-78XJ
5.3

GHSA-m3qr-fvp4-78xj: Authentication Bypass and Log Disclosure in Basekick Labs Arc

GHSA-m3qr-fvp4-78xj is an authentication bypass and information disclosure vulnerability in Arc, an open-source, SQL-native time-series database developed by Basekick Labs and written in Go. Due to an improper route registration sequence within the Go Fiber HTTP server initialization pipeline, the application registered the /api/v1/logs endpoint prior to mounting the global authentication middleware. Because Fiber evaluates route handlers in strict declaration order and terminates request traversal when a handler returns without invoking c.Next(), unauthenticated remote callers can query the logs endpoint and retrieve up to 10,000 buffered operational log entries even when authentication is enabled.

Alon Barad
Alon Barad
7 views•8 min read
•about 19 hours ago•CVE-2026-62848
7.3

CVE-2026-62848: Local Arbitrary Code Execution via Unsafe Deserialization in Metalama Named Pipe IPC

CVE-2026-62848 (GHSA-h26j-4vp7-x9w2) is a high-severity unsafe deserialization vulnerability in Metalama, a Roslyn-based meta-programming and code generation framework for C#. The flaw resides in the inter-process communication (IPC) channel used by Metalama within Microsoft Visual Studio. Across versions 2023.0 through 2026.1.18, the framework utilized either Newtonsoft.Json with TypeNameHandling.All or MessagePack with TypelessObjectResolver over local Windows named pipes without enforcing a strict type allow-list. Because the named pipes use predictable identifiers, any local process running under the same Windows user session can connect to the endpoint and transmit crafted serialized payloads, resulting in arbitrary Common Language Runtime (CLR) type instantiation and code execution within the host Visual Studio process.

Alon Barad
Alon Barad
10 views•9 min read
•about 20 hours ago•GHSA-9PPR-WFW9-XVR2
5.3

GHSA-9ppr-wfw9-xvr2: DNS Cache TTL Manipulation Failure in Netfoil via Go Value-Copy Range Iteration

A logic flaw in github.com/tinfoil-factory/netfoil versions 0.3.0 through 0.6.0 prevents the DNS proxy from properly decrementing Time-To-Live (TTL) values on cached DNS responses and enforcing configured maximum TTL limits. Due to an idiomatic Go programming mistake where a range loop modifies value copies of slice elements rather than the underlying slice array, netfoil continually serves DNS answers with their original static TTLs. This condition causes downstream clients and resolvers to retain stale DNS records beyond their intended expiration window and bypasses local MaxTTL administrative policies.

Alon Barad
Alon Barad
7 views•10 min read
•about 21 hours ago•CVE-2026-11800
8.1

CVE-2026-11800: Authentication Bypass via JWT Algorithm Confusion in Keycloak

A cryptographic signature verification flaw in Keycloak's OAuth 2.0 JWT Authorization Grant flow (RFC 7523) and federated client authentication mechanisms allows algorithm confusion between asymmetric and symmetric signing algorithms. Authenticated clients can sign forged JWT assertions using HMAC-SHA256 (HS256) with an Identity Provider's public key bytes acting as the symmetric secret. Keycloak processes the public key material as an HMAC secret key, validating the forged assertion and issuing unauthorized access tokens for federated users.

Alon Barad
Alon Barad
9 views•10 min read