Oct 6, 2026·6 min read·4 visits
Unauthenticated attackers can bypass read-access controls on restricted collections via nested query parameters on related public collections, leaking metadata and confirming document existence.
An authorization bypass vulnerability in Payload CMS enables unauthenticated attackers to query and infer the existence of restricted documents via nested relationship queries on public collections. This cross-document contamination flaw affects both MongoDB and Drizzle SQL database adapters, allowing unauthorized reads of relationship metadata.
Payload CMS utilizes a collection-based data model where documents can establish relationships with documents in other collections using relationship, upload, or join fields. Access control in Payload CMS is applied at the collection level through authorization rules defined in the schema. When a user requests a collection, Payload CMS evaluates these rules and injects matching query constraints to restrict the returned dataset to only authorized documents.
This vulnerability arises from an authorization alignment misalignment when querying a publicly readable parent collection that contains relationships pointing to a restricted collection. Attackers can execute nested query parameters targeting fields within the restricted collection. Because the query parser evaluates the user's search criteria and the security restrictions independently, unauthenticated users can bypass the access.read policies of the related collection.
The flaw behaves as a related-document oracle or a cross-document contamination channel. While the attacker cannot directly fetch the full contents of the unauthorized documents, they can leverage the public endpoints to verify the existence of specific restricted documents, probe sensitive fields, and extract relationship metadata.
The root cause of this vulnerability lies in the independent resolution of user-supplied filters and system-enforced authorization policies across multi-document relationships. When an incoming query filters on a related document field, the query builder constructs the query differently depending on the active database adapter, but both adapters suffered from logical decoupling.
In the MongoDB adapter, queries targeting relationships (such as arrays of document IDs) were evaluated using implicit array matching. When a query is structured as { $and: [ { 'posts.title': 'archived' }, { 'posts.title': { $ne: 'archived' } } ] }, MongoDB satisfies this query if any element in the array matches the first condition, and any element (even a completely different one) matches the second condition. If a parent document links to one archived post and one public post, the query evaluates to true, leaking the relationship to the restricted archived document.
In the Drizzle SQL adapter, the query engine generated distinct table JOIN clauses for the user-supplied query and the injected authorization constraints. Because these constraints were evaluated on different alias variables representing distinct rows in the joined database table, the relational database matched parent records that had any association with an authorized row, regardless of whether the specific row matching the user's filter was authorized.
The vulnerability was mitigated in commit 94059cf4bc6170ce88453015c0c6551329ae3982 by rewriting the query compilers to evaluate user-supplied filters and access-control criteria against the exact same related document.
In the MongoDB adapter (packages/db-mongodb/src/queries/buildSearchParams.ts), the query parser now isolates relationship filters by executing a sub-query directly against the model of the related collection. This sub-query enforces access-control parameters within the target collection context first, then returns only the authorized IDs using the $in operator:
// Directly build the query on the related model (which automatically injects access control)
const matchingRelatedDocumentsQuery = await RelatedModel.buildQuery({
locale: pathLocale ?? locale,
payload,
where: nestedWhere,
})
// Retrieve authorized and matching related document IDs only
const matchingRelatedDocumentIDs = (
await RelatedModel.find(matchingRelatedDocumentsQuery).lean().select({ _id: true })
).map((document) => document._id)
// Enforce parent query to match using $in against ONLY verified/authorized IDs
return {
path,
value: { $in: matchingRelatedDocumentIDs },
}In the Drizzle/SQL adapter (packages/drizzle/src/queries/parseParams.ts), the SQL query compiler was corrected to reuse the exact same join table alias variable. This forces SQL engines to apply both the user filter and the authorization rules within the same JOIN context rather than creating duplicate joins.
> [!WARNING]
> Scale-Based Denial of Service (DoS) Risk:
> In the MongoDB mitigation, the query engine retrieves all matching related document IDs into memory before passing them to the parent query via an $in clause. For collections containing millions of matching records, this execution path can result in substantial memory pressure, network latency, and potential application crashes if the retrieved document ID list exceeds memory bounds or MongoDB's BSON document limits.
Exploitation of this vulnerability requires no authentication and can be completed through standard API query structures. Consider an application with a restricted posts collection and a public post-references collection containing a relationship field pointing to posts.
An administrator configures an authorization constraint on the posts collection to hide archived items from unauthenticated guests:
// posts read-access policy
read: ({ req }) => (req.user ? true : { title: { not_equals: 'archived' } })An unauthenticated attacker sends an HTTP request querying the public collection, searching specifically for related records that are marked as 'archived'. The request is structured as follows:
GET /api/post-references?where[post.title][equals]=archived HTTP/1.1
Host: vulnerable-payload-cms.local
Accept: application/jsonBefore the patch, the application returns the parent post-reference document containing the reference ID of the restricted post, confirming that a post titled 'archived' exists. After applying the patch, the query returns an empty dataset because no single referenced post satisfies both conditions simultaneously (being titled 'archived' and not being titled 'archived').
The security impact of CVE-2026-105852 is classified as a medium-severity authorization bypass. Because the vulnerability targets relationship boundaries, an attacker cannot extract arbitrary database columns unless those columns are explicitly referenced within nested where queries.
However, this vulnerability constitutes a highly reliable side-channel oracle. Attackers can programmatically brute-force and deduce the values of restricted fields (e.g., verifying draft article titles, leaking user identifiers, or mapping out confidential relational links). This metadata leakage is critical in environments where the existence of a link itself is sensitive information, such as medical systems, private repositories, or multi-tenant database environments.
Furthermore, the severity escalates if combined with performance bugs or other logical flaws. The database adapter's structural limits could be triggered intentionally, allowing attackers to construct nested queries on large collections to degrade system performance.
To fully remediate this vulnerability, organizations must upgrade all core Payload CMS packages and associated database adapters to version 3.90.0 or higher, or canary versions >= 4.0.0-canary.34.
Execute the dependency update using the appropriate package manager:
npm install payload@latest @payloadcms/db-mongodb@latest @payloadcms/db-postgres@latestIf immediate patching is not possible, implement the following defensive actions:
relationship, upload, or join fields that connect public collections to restricted target collections.CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
payload payloadcms | < 3.90.0 | 3.90.0 |
payload payloadcms | >= 4.0.0-canary.0 < 4.0.0-canary.34 | 4.0.0-canary.34 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862 (Missing Authorization) |
| Attack Vector | Network (AV:N) |
| CVSS v4.0 Score | 5.3 (Medium) |
| EPSS Score | Not Available |
| Impact | Information Disclosure / Related-Document Oracle |
| Exploit Status | Proof of Concept (PoC) documented in integration test suite |
| KEV Status | Not Listed |
The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
A critical access control bypass vulnerability (CVE-2026-105851) in Payload CMS allows authenticated users to bypass field-level access controls during document duplication. By duplicating high-privilege documents, such as administrator accounts, standard users can inherit sensitive fields (e.g., role configurations or API keys), leading to privilege escalation.
CVE-2026-105853 is a high-severity information disclosure vulnerability in Payload CMS that affects authentication-enabled collections. In vulnerable versions, the application fails to properly serialize and sanitize user documents during token refresh and password reset operations. This deficiency leaks hidden and read-restricted fields to unauthorized actors. Additionally, a logical flaw in token refresh validation allows low-privileged users to cross collection boundaries, exposing sensitive configuration details and administrative metadata.
A high-severity race condition vulnerability exists in @payloadcms/plugin-ecommerce within the Stripe payment adapter's order confirmation pipeline. Unauthenticated attackers or parallel webhook deliveries can exploit sequential, non-atomic database operations to bypass state verifications, leading to duplicate order creation, multiple inventory decrements, and inconsistent database records.
A sensitive data exposure vulnerability in Payload CMS allows authenticated low-privilege users to retrieve decrypted, plaintext API keys of other users, including administrators, leading to full administrative account takeover and privilege escalation.
CVE-2026-86540 is a high-severity arbitrary code execution vulnerability in knowns, a repository management tool. The vulnerability occurs when the application parses and executes unvalidated language server binary overrides defined within a project's local configuration file.
Payload CMS, a popular open-source headless Content Management System, contains a critical Regular Expression Denial of Service (ReDoS) and uncontrolled resource consumption vulnerability in versions prior to 3.90.0 and canary versions prior to 4.0.0-canary.34. Due to nested quantifiers in the multipart boundary regex validation pattern, and the absence of streaming backpressure controls, remote attackers can trigger catastrophic backtracking and memory exhaustion. This blocks the single-threaded Node.js event loop, resulting in a persistent and complete Denial of Service (DoS).