CVE-2026-39857 Overview
ApostropheCMS, an open-source Node.js content management system, contains an authorization bypass vulnerability in versions 4.28.0 and prior. The vulnerability exists in the choices and counts query parameters of the REST API, where these query builders execute MongoDB distinct() operations that bypass the publicApiProjection restrictions intended to limit which fields are exposed publicly.
Critical Impact
Unauthenticated attackers can extract all distinct field values for protected schema fields, including sensitive data protected by viewPermission, without authentication.
Affected Products
- ApostropheCMS versions 4.28.0 and prior
- ApostropheCMS piece-type REST API
- ApostropheCMS page REST API
Discovery Timeline
- 2026-04-15 - CVE-2026-39857 published to NVD
- 2026-04-16 - Last updated in NVD database
Technical Details for CVE-2026-39857
Vulnerability Analysis
This authorization bypass vulnerability stems from a fundamental mismatch between how ApostropheCMS applies security projections and how MongoDB's distinct() operation functions. The choices and counts query parameters are processed via applyBuildersSafely before the projection is applied, but MongoDB's distinct operation does not respect projections, returning all distinct values directly.
The vulnerability affects multiple field types including string, integer, float, select, boolean, date, slug, and relationship fields. Fields protected with viewPermission are similarly exposed, and the counts variant additionally reveals document frequency for each distinct value. This information disclosure can be leveraged to enumerate sensitive data, understand data distributions, or gather reconnaissance for further attacks.
Root Cause
The root cause is the architectural disconnect between MongoDB's distinct() operator behavior and ApostropheCMS's projection-based access control model. When publicApiProjection is configured to restrict public API access to specific fields, the choices and counts query builders bypass this protection because:
- The parameters are processed via applyBuildersSafely before projections are applied
- MongoDB's distinct operation inherently ignores projection constraints
- Results are returned without filtering against publicApiProjection or removeForbiddenFields
Attack Vector
An unauthenticated attacker can exploit this vulnerability remotely over the network by crafting malicious REST API requests. By specifying protected field names in the choices or counts query parameters, attackers can extract distinct values that should be restricted by publicApiProjection. The attack requires no user interaction and can be performed with low complexity against any exposed ApostropheCMS instance running vulnerable versions.
The security patch introduces a new choicesFieldAllowedByProjection method that validates whether a filter is permitted to expose distinct values based on the active publicApiProjection:
// Returns true if the named filter is permitted to expose distinct
// values through the `choices` / `counts` query builders given the
// publicApiProjection. When no publicApiProjection is in effect
// (authenticated API callers), all fields are permitted.
//
// This guards against leaking distinct values of fields excluded by
// `publicApiProjection`, since MongoDB's `distinct` operator ignores
// projections. Projections set explicitly by authenticated users are
// not restricted — they are a voluntary narrowing of query results,
// not a security boundary.
choicesFieldAllowedByProjection(filter, projection) {
if (!projection || !Object.keys(projection).length) {
return true;
}
// Builders that aren't named after a top-level schema field are
// not gated by the projection.
const field = self.schema.find(f => f.name === filter);
if (!field) {
return true;
}
const topLevel = filter.split('.')[0];
const values = Object.values(projection);
const hasInclusion = values.some(v => v && v !== 0);
const hasExclusion = values.some(v => v === 0 || v === false);
if (hasInclusion) {
// Inclusion projection: field must be explicitly included.
return Boolean(projection[topLevel]);
Source: GitHub Commit
Detection Methods for CVE-2026-39857
Indicators of Compromise
- Unusual API requests containing choices or counts query parameters targeting protected fields
- High-volume REST API requests from unauthenticated sources querying field metadata
- API access logs showing requests to piece-type or page endpoints with enumeration patterns
Detection Strategies
- Monitor web server access logs for REST API requests containing choices= or counts= query strings
- Implement rate limiting on public API endpoints to detect enumeration attempts
- Review application logs for unusual patterns of unauthenticated API access
- Deploy Web Application Firewall (WAF) rules to flag suspicious query parameter combinations
Monitoring Recommendations
- Enable detailed logging for all REST API endpoints exposing content types
- Set up alerts for anomalous API request patterns from single IP addresses
- Monitor for sequential requests attempting to enumerate multiple field types
- Track authentication bypass attempts through security information and event management (SIEM) systems
How to Mitigate CVE-2026-39857
Immediate Actions Required
- Upgrade ApostropheCMS to version 4.29.0 or later immediately
- Review publicApiProjection configurations to ensure sensitive fields are properly protected
- Audit API access logs for evidence of prior exploitation attempts
- Temporarily disable public API access if immediate patching is not possible
Patch Information
The vulnerability has been fixed in ApostropheCMS version 4.29.0. The patch introduces the choicesFieldAllowedByProjection method in @apostrophecms/doc-type module and properly propagates publicApiProjection settings in the @apostrophecms/page module. The fix ensures that MongoDB distinct() operations respect the same field-level access controls as other API operations.
For detailed information about the fix, refer to the GitHub Security Advisory GHSA-c276-fj82-f2pq and the security patch commit.
Workarounds
- Restrict public API access using network-level controls (firewall rules, IP allowlisting)
- Implement additional authentication requirements for API endpoints exposing sensitive content
- Use reverse proxy configuration to block requests containing choices or counts parameters for unauthenticated users
# Example nginx configuration to block vulnerable parameters for unauthenticated requests
location /api/ {
# Block choices and counts parameters for public access
if ($arg_choices) {
return 403;
}
if ($arg_counts) {
return 403;
}
proxy_pass http://apostrophecms_backend;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

