Every CVE Search/ Get API key

CVE-2026-113655

ApostropheCMS: Same-parent page reorder in @apostrophecms/page move() re-ranks a restricted parent's children without create authorization

4.3 MediumFix available

ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an authenticated editor with legitimate edit rights on a pre-existing ordinary page nested under a restricted parent can use the same-parent page move operation to change sibling ranks without create authorization on that parent. The non-default nesting must already exist, and the bypass is limited to sibling ordering rather than arbitrary content modification, confidentiality loss, or creation of the restricted nesting. This issue is fixed in version 4.33.0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
Low
Availability
None

Exploit likelihood

0.32%Unchanged since Oct 21, 2026
90%50%10%1%

What each source reports

CVE List Score used 4.3

ApostropheCMS: Same-parent page reorder in @apostrophecms/page move() re-ranks a restricted parent's children without create authorization

ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an authenticated editor with legitimate edit rights on a pre-existing ordinary page nested under a restricted parent can use the same-parent page move operation to change sibling ranks without create authorization on that parent. The non-default nesting must already exist, and the bypass is limited to sibling ordering rather than arbitrary content modification, confidentiality loss, or creation of the restricted nesting. This issue is fixed in version 4.33.0.

Record
CVE-2026-113655
CVSS 3.1
4.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-639, CWE-862
Updated
2026-11-02
EUVDEUVD-2026-105183 4.3

ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an authenticated editor with legitimate edit rights on a pre-existing ordinary page nested under a restricted parent can use the same-parent page move operation to change sibling ranks without create authorization on that parent. The non-default nesting must already exist, and the bypass is limited to sibling ordering rather than arbitrary content modification, confidentiality loss, or creation of the restricted nesting. This issue is fixed in version 4.33.0.

Record
EUVD-2026-105183
CVSS 3.1
4.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-2jrp-qc93-h2j8 4.3

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 siblings are modified with no authorization at all.

Affected function: @apostrophecms/page move() (inner body)
  packages/apostrophe/modules/@apostrophecms/page/index.js:1684-1691
    if (
      (oldParent._id !== parent._id) &&               // false for a same-parent reorder -> whole check skipped
      (parent.type !== '@apostrophecms/archive-page') &&
      (!parent._create) &&
      !(oldParent.type === '@apostrophecms/archive-page' && parent._edit)
    ) {
      throw self.apos.error('forbidden');
    }

Unguarded sink: nudgeNewPeers()
  packages/apostrophe/modules/@apostrophecms/page/index.js:1781-1803
    await self.apos.doc.db.updateMany(
      { path: matchDescendants(parent), level: parent.level + 1,
        aposLocale: { $in: [ draft, published ] }, rank: { $gte: rank } },
      { $inc: { rank: 1 } });   // no permission clause; bypasses beforeUpdate

Contrasting correct boundary: insert()
  packages/apostrophe/modules/@apostrophecms/page/index.js:1436-1439
    if (!parent._create) { throw self.apos.error('forbidden'); }  // enforced for every position

Impact

The attacker is an authenticated low-privileged user, an editor (or a contributor operating in draft mode), who holds edit rights on at least one ordinary page that is nested as a direct child of a restricted-type parent. No admin rights and no special tokens are required. Authorization in this CMS is resolved per page type, not per subtree: a page's editability is judged by its own type's editRole, so an ordinary public-page child can be editable by an editor even though its restricted secret-page-type parent (declaring editRole: admin) is not. Exploiting the gap, the editor can persistently alter the rank (sibling ordering, which drives navigation and menu order) of the restricted parent's other children, documents on which the editor holds no edit, create, publish, or delete authority. Repeating the reposition monotonically inflates those siblings' ranks. This is an…

Record
GHSA-2jrp-qc93-h2j8
CVSS 3.1
4.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-639, CWE-862
Updated
2026-11-02
NVD 4.3

ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an authenticated editor with legitimate edit rights on a pre-existing ordinary page nested under a restricted parent can use the same-parent page move operation to change sibling ranks without create authorization on that parent. The non-default nesting must already exist, and the bypass is limited to sibling ordering rather than arbitrary content modification, confidentiality loss, or creation of the restricted nesting. This issue is fixed in version 4.33.0.

Record
CVE-2026-113655
CVSS 3.1
4.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-639, CWE-862
Updated
2026-11-02
OSV 4.3

ApostropheCMS: Same-parent page reorder in @apostrophecms/page move() re-ranks a restricted parent's children without create authorization

ApostropheCMS is an open-source Node.js content management system. Prior to 4.33.0, an authenticated editor with legitimate edit rights on a pre-existing ordinary page nested under a restricted parent can use the same-parent page move operation to change sibling ranks without create authorization on that parent. The non-default nesting must already exist, and the bypass is limited to sibling ordering rather than arbitrary content modification, confidentiality loss, or creation of the restricted nesting. This issue is fixed in version 4.33.0.

Record
CVE-2026-113655
CVSS 3.1
4.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-639, CWE-862
Updated
2026-11-02
OSVGHSA-2jrp-qc93-h2j8 4.3

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 siblings are modified with no authorization at all.

Affected function: @apostrophecms/page move() (inner body)
  packages/apostrophe/modules/@apostrophecms/page/index.js:1684-1691
    if (
      (oldParent._id !== parent._id) &&               // false for a same-parent reorder -> whole check skipped
      (parent.type !== '@apostrophecms/archive-page') &&
      (!parent._create) &&
      !(oldParent.type === '@apostrophecms/archive-page' && parent._edit)
    ) {
      throw self.apos.error('forbidden');
    }

Unguarded sink: nudgeNewPeers()
  packages/apostrophe/modules/@apostrophecms/page/index.js:1781-1803
    await self.apos.doc.db.updateMany(
      { path: matchDescendants(parent), level: parent.level + 1,
        aposLocale: { $in: [ draft, published ] }, rank: { $gte: rank } },
      { $inc: { rank: 1 } });   // no permission clause; bypasses beforeUpdate

Contrasting correct boundary: insert()
  packages/apostrophe/modules/@apostrophecms/page/index.js:1436-1439
    if (!parent._create) { throw self.apos.error('forbidden'); }  // enforced for every position

Impact

The attacker is an authenticated low-privileged user, an editor (or a contributor operating in draft mode), who holds edit rights on at least one ordinary page that is nested as a direct child of a restricted-type parent. No admin rights and no special tokens are required. Authorization in this CMS is resolved per page type, not per subtree: a page's editability is judged by its own type's editRole, so an ordinary public-page child can be editable by an editor even though its restricted secret-page-type parent (declaring editRole: admin) is not. Exploiting the gap, the editor can persistently alter the rank (sibling ordering, which drives navigation and menu order) of the restricted parent's other children, documents on which the editor holds no edit, create, publish, or delete authority. Repeating the reposition monotonically inflates those siblings' ranks. This is an…

Record
GHSA-2jrp-qc93-h2j8
CVSS 3.1
4.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-639, CWE-862
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
apostrophe
npm
before 4.33.0
4.33.0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-113655 is a medium vulnerability (CVSS 4.3) in Apostrophecms Apostrophe, published October 20, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 25th percentile. Fixed in apostrophe 4.33.0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open