GHSA-2jrp-qc93-h2j8 - ApostropheCMS: Same-parent page reorder in @apostrophecms/page move() re-ranks a restricted parent's children without create authorization
## Summary
ApostropheCMS enforces per-type authorization on pages: a page type may declare `editRole` / `publishRole` (the core `@apostrophecms/archive-page` does), so a project can define restricted subtrees that only higher-privileged roles may create or edit within. The `move()` operation in the `@apostrophecms/page` module is supposed to enforce that a page may only be moved into a parent the actor has `create` rights over, the same boundary the page-insert route enforces. The destination-parent authorization check in `move()` is gated on the move being a cross-parent move (`oldParent._id !== parent._id`). A same-parent reorder (repositioning a page among its existing siblings under the same parent) short-circuits that check entirely, so an authenticated low-privileged editor who holds edit rights on one ordinary page nested under a restricted parent can reposition it and, in doing so, trigger an unguarded bulk database write that re-ranks the restricted parent's other children, documents the editor has no authorization to modify.
## Root Cause
The security invariant is that mutating the sibling ordering of a restricted parent's children requires `create` authority on that parent, which is exactly what the page-insert path enforces (`insert()` throws `forbidden` when `!parent._create` before it nudges peers). The destination authorization guard in `move()` restores this boundary only for cross-parent moves: its leading conjunct is `(oldParent._id !== parent._id)`. For a same-parent reorder both `oldParent` and `parent` are the identical restricted parent, so the conjunct is `false`, the whole conditional short-circuits, and the `parent._create` requirement is never evaluated. The only surviving gate on the path is `moved._edit`, which the editor legitimately holds for the ordinary page being moved. The subsequent sibling re-rank is issued as a raw MongoDB `updateMany` that never passes through the per-document `beforeUpdate` edit check, so the restricted sibl
MEDIUM
Severity & confidence
Source severitymedium
Platform severitymedium
Confidencemedium
Exploitationunknown
CVSS4.3
Affected
Vendorsapostrophe
Productsapostrophe
Reporting sources (1)
GitHub Security Advisories
Timeline & provenance
Published2026-10-20T18:04:11
Last updated2026-10-21T07:49:05
Ingested2026-10-20T18:05:01
FreshnessNEAR-REAL-TIME
Threat typeadvisory
Recommended action
Review the advisory and upgrade affected packages to the first patched version.
Next steps
- Identify affected systems in your environment.
- Apply the vendor patch or mitigation guidance.
- Review logs for indicators described in the advisory.
- Follow the affected vendor/product to track updates.
Confidence explanation
Reported by a single or secondary source; treat as indicative, verify before acting.
Source type: vendor ยท Original: GitHub Security Advisories