CVE-2026-63669 Overview
ApostropheCMS, an open-source Node.js content management system, contains a broken access control flaw in the page module's move() operation. Prior to version 4.32.0, the destination parent's _create permission check is bypassed because the archive condition disables enforcement for ordinary moves. An authenticated editor or contributor can send _targetId and _position values through the page REST update endpoint to move a controlled page into a restricted subtree. The nudgeNewPeers()updateMany operation then re-ranks protected sibling pages, allowing tampering with content the actor should not modify. The vulnerability is classified under [CWE-639: Authorization Bypass Through User-Controlled Key].
Critical Impact
Authenticated low-privilege users can bypass destination-parent authorization to reorder and interfere with protected pages in restricted subtrees.
Affected Products
- ApostropheCMS versions prior to 4.32.0
- The @apostrophecms/page module move() operation
- Deployments using the page REST update endpoint with editor or contributor roles
Discovery Timeline
- 2026-08-17 - CVE-2026-63669 published to NVD
- 2026-08-17 - Last updated in NVD database
Technical Details for CVE-2026-63669
Vulnerability Analysis
The flaw resides in the page move authorization guard within packages/apostrophe/modules/@apostrophecms/page/index.js. The guard is intended to enforce _create permission on the destination parent whenever a page moves across parents into a non-archive destination. A logic error in the boolean expression instead gates the entire _create check on the source parent being the archive. For ordinary cross-parent moves, the check collapses to false and never fires.
An authenticated editor or contributor can exploit this by supplying _targetId and _position parameters to the page REST update endpoint. The server accepts the request and moves a page the actor controls into a restricted subtree. As part of the move, nudgeNewPeers() issues an updateMany that re-ranks sibling pages in that subtree, including pages the actor has no authorization to modify.
Root Cause
The root cause is an incorrectly composed authorization predicate. The archive exception was ANDed onto the guard in its unnegated form rather than negated and ANDed onto it. This turned a narrow exception, restoring a page out of the archive, into a blanket bypass of the _create requirement on every normal move.
Attack Vector
The attacker requires a valid authenticated session with editor or contributor privileges. Exploitation occurs over the network via the page REST update endpoint. No user interaction is needed. The confidentiality impact is none, but integrity impact is high because protected sibling pages can be re-ranked and structural relationships can be altered.
// Security patch in packages/apostrophe/modules/@apostrophecms/page/index.js
// Move outside tree
throw self.apos.error('forbidden');
}
+ // Enforce destination-parent authorization: a cross-parent move
+ // into a non-archive destination requires "create" permission on
+ // that destination (the same boundary the page-insert route
+ // enforces). The one exception is restoring a page out of the
+ // archive, which is permitted into any destination the actor may
+ // edit even without "create".
+ //
+ // The exception must be negated and ANDed onto the guard, NOT ANDed
+ // on unnegated: doing the latter (a past regression, GHSA-wr5r-wqp2-
+ // x4fh) gated the whole check on "moving out of the archive" and
+ // disabled create enforcement for every normal move.
if (
(oldParent._id !== parent._id) &&
(parent.type !== '@apostrophecms/archive-page') &&
(!parent._create) &&
- (oldParent.type === '@apostrophecms/archive-page' && !parent._edit)
+ !(oldParent.type === '@apostrophecms/archive-page' && parent._edit)
) {
throw self.apos.error('forbidden');
}
Source: ApostropheCMS commit d50c6ad
Detection Methods for CVE-2026-63669
Indicators of Compromise
- Page REST update requests from editor or contributor accounts containing _targetId and _position parameters targeting parents outside the actor's normal working subtree.
- Unexpected changes in page rank values on protected sibling pages, particularly bursts of re-ranking driven by nudgeNewPeers()updateMany operations.
- Move operations where the destination parent's _create permission is false for the acting user but the move nonetheless succeeded.
Detection Strategies
- Audit ApostropheCMS application logs for successful page move operations correlated to users lacking _create on the destination parent.
- Compare historical page tree snapshots to identify unauthorized structural or ordering changes to protected subtrees.
- Instrument the page module to log the resolved permissions on both source and destination parents for every move request.
Monitoring Recommendations
- Alert on any HTTP requests to the page REST update endpoint that include _targetId values referencing pages outside the caller's authorized workspace.
- Track the frequency and scope of updateMany operations on the pages collection, focusing on unexpected re-rank events.
- Monitor MongoDB audit logs for bulk updates against the pages collection originating from non-administrative sessions.
How to Mitigate CVE-2026-63669
Immediate Actions Required
- Upgrade ApostropheCMS to version 4.32.0 or later, which restores correct destination-parent authorization enforcement in the move() operation.
- Review and, where necessary, revoke editor and contributor permissions granted to untrusted users until the upgrade is complete.
- Inspect the page tree for unauthorized moves or rank changes to protected subtrees and restore from backup if tampering is confirmed.
Patch Information
The fix is included in ApostropheCMS 4.32.0. The patch negates the archive exception and ANDs it onto the guard, restoring the intended behavior that cross-parent moves into non-archive destinations require _create on the destination. Details are documented in the GitHub Security Advisory GHSA-wr5r-wqp2-x4fh and the upstream commit.
Workarounds
- Restrict editor and contributor roles to a minimum set of trusted users until the upgrade to 4.32.0 is deployed.
- Add a reverse proxy or application-layer rule that blocks page REST update requests containing _targetId or _position from non-administrative accounts.
- Manually enforce destination-parent authorization in a custom module override until the official patch is applied.
# Upgrade ApostropheCMS to the patched release
npm install @apostrophecms/apostrophe@^4.32.0
npm ls @apostrophecms/apostrophe
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

