
Joomla 6.1.3 - High - Remote - ACL - GET /api/v1/users/levels leaks view levels
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · joomla-levels-api
Class: Privilege leftover Reach: Remote
Joomla CMS 6.1.3 (0f2d4de) - Open Source Matters
Administrator Users -> Viewing Access Levels requires core.admin on com_users (LevelController::allowSave and delete). The Groups webservice already does the same (GroupsController, 6.1.1). LevelsController has no allowAdd, allowEdit, or delete override, so ApiController lets core.manage plus core.create through.
A Manager-class API token, granted core.login.api without core.admin, can create viewing access levels the UI forbids.
| ID | no CVE yet |
| Class | Privilege leftover / authorization bypass |
| Reach | Remote (API token with core.login.api) |
| CWE | CWE-863 |
| CVSS | Medium: 6.1 CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N |
| Product | Joomla CMS |
| Affected | 6.1.3 (0f2d4de4729eb951e0878fec98c7990da07915b2) |
| Auth | API token for Manager (group 6) with core.login.api and com_users manage/create/edit. No core.admin. Default core.login.api is Super User only. |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
Use a non-Super-User API token to change which groups see which pages. They do not become Super User from this leftover alone. This is content-visibility control, not a site takeover.
| Privilege | Method / path | Kind | Lab-proven or inferred |
|---|---|---|---|
| Create a viewing access level | POST /api/index.php/v1/users/levels JSON title, rules (group ids) | integrity | Lab-proven. HTTP 200, #__viewlevels id=7, title poc-level-JOOMLA-LEVELS-API-WITNESS |
| Edit an existing level (group list / title) | PATCH /api/index.php/v1/users/levels/{id} | integrity | Inferred. Same controller, no allowEdit. Lab created only. |
| Delete a level | DELETE /api/index.php/v1/users/levels/{id} | integrity / availability of ACL rows | Inferred. Same missing override. Lab did not DELETE. |
| Expose a members-only article, module, or menu item | New or patched level whose rules include Public / Guest / Registered | recon (content visibility) | Inferred from #__viewlevels.rules. Lab inserted the row; it did not re-ACL a live article. |
| Hide a page from Registered, or add the attacker's group to a Special level | Same PATCH / create | integrity | Inferred. Same store. |
| Mutate user groups from the API | POST /api/index.php/v1/users/groups | n/a | Lab-proven closed. HTTP 403 (GroupsController core.admin) |
| Open Users -> Viewing Access Levels in administrator | GET /administrator/index.php?option=com_users&view=levels | n/a | Lab-proven closed. HTTP 403 |
| Save a level from the UI | POST ... task=level.save | n/a | Lab-proven closed. HTTP 403 (LevelController::allowSave requires core.admin) |
Hit the API with a stock Manager (no core.login.api) | Bearer token / X-Joomla-Token | n/a | Inferred closed. Default core.login.api is Super User (group 8) only. This lab grants it to group 6 first. |
| Super User / installer RCE | n/a | n/a | Closed. Manager stays Manager. |
I pinned joomla/joomla-cms 6.1.3 after the 2026-07/08 JSST wave. Groups API already requires core.admin. View levels still fall through ApiController (core.manage plus core.create / core.edit / core.delete). The only extra logic on LevelsController is PATCH JSON decode of rules.
Fixed Groups sibling:
public function allowAdd($data = [])
{
return $this->app->getIdentity()->authorise('core.admin', $this->option);
}
Administrator UI:
protected function allowSave($data, $key = 'id')
{
return $this->app->getIdentity()->authorise('core.admin', $this->option)
&& parent::allowSave($data, $key);
}
Wrong turns already recorded: treating Groups API as still open (it is 403); hitting the API as a stock Manager without granting core.login.api first (default is Super User only, same setup as CVE-2026-71574 / 72531 / 48904); reading UI 403 as the whole story (the leftover is the API). Theatre: a reverse shell. The oracle is API 200 plus Groups 403 plus UI 403.
Same pin leftovers: menu items API, media override, articles catid.
python3 joomla-levels-api-Abraxas-Labs.py
or
cd lab
./run.sh
Target only http://127.0.0.1:19520. Image joomla:6.1.3-php8.3-apache plus mariadb:11.4.
SUCCESS joomla-levels-api api-http=200 level-id=7 groups-api=403 ui-view=403 ui-save=403 JOOMLA-LEVELS-API-WITNESS
Copy GroupsController core.admin allowAdd / allowEdit / delete onto LevelsController. Keep the administrator UI gate.
0f2d4de4729eb951e0878fec98c7990da07915b2)LevelsController.phpcore.admin (6.1.1) · CVE-2026-71574GNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.