# phpMyFAQ has an incomplete fix for GHSA-xvp4-phqj-cjr3 — editUser() and updateUserRights() lack authorization guards

phpMyFAQ 4.1.3's fix for an IDOR ATO left editUser() and updateUserRights() unguarded, letting a non-SuperAdmin admin set is_superadmin=true and escalate to SuperAdmin.

- Payout: Research
- Severity: high
- Program: phpMyFAQ
- Found by: SnailSploit, 0xShemesh
- Disclosed: 2026-06-26
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-985r-q3qp-299h
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-985r-q3qp-299h
- Tags: area:web domain:web impact:privesc kind:research platform:ghsa sev:high tech:php technique:incomplete-fix technique:source-review vuln:access-control vuln:idor vuln:privilege-escalation

**Target:** Admin API user controller endpoints (edit, update-rights)
**Root cause:** The 4.1.3 patch added isSelf/isSuperAdmin/target-protection guards only to overwritePassword(); sibling methods editUser() and updateUserRights() in the same controller still gate solely on userHasPermission(USER_EDIT), which non-SuperAdmins can hold, and pass user-controlled userId/is_superadmin into setSuperAdmin() and grantUserRight().
**Steps:**
1. Authenticate as a non-SuperAdmin admin holding the delegable edit_user right.
2. Obtain the CSRF token for update-user-data from an admin page.
3. POST to `admin/api/user/edit` with own userId and `is_superadmin=true`; controller reaches `$user->setSuperAdmin((bool)$isSuperAdmin)` at UserController.php:463 with no isSuperAdmin check.
4. Account's is_superadmin flips 0→1 in faquser, granting full SuperAdmin.
5. Alternatively POST to `admin/api/user/update-rights` with arbitrary userId to `grantUserRight($userId, …)` at :511.
**How found:** Incomplete-fix audit: read the 4.1.3 patch for GHSA-xvp4-phqj-cjr3, noted its stated invariant ('non-SuperAdmin must never alter a SuperAdmin'), then walked sibling methods in the same UserController file and found the identical userId→getUserById→privileged-mutation primitive without the new guards; confirmed via git diff that editUser/updateUserRights/setSuperAdmin were untouched.
**Exploitation:** An authenticated admin with only edit_user sends a CSRF-tokened request to admin/api/user/edit setting is_superadmin=true on their own account, escalating to SuperAdmin; or grants arbitrary rights to any account via update-rights.
**Escalation:** Self-promotion to SuperAdmin yields full control over users, config and content; update-rights allows granting rights the actor does not hold.
**Insight:** When a patch introduces a security invariant in code comments, grep the same file/class for every other method sharing the same user-controlled-key→privileged-sink shape; the fix diff itself tells you which siblings were skipped.

