Joomla, menu items API skips per-menutype ACL
Administrator menu items check com_menus.menu.{id} and block menutype main. The webservice ItemsController has no allowAdd. A token user who may manage one menu can plant items on staff menus and admin main. Labbed 6.1.3.
- Name
- Joomla, menu items API skips per-menutype ACL
- Type
- 0-day analysis
- CVE
- n/a
- CVE Risk
- high
- Disclosure Status
- public
- Vendor
- Joomla
- Affected
- Joomla CMS 6.1.3 (0f2d4de). API token with core.login.api plus com_menus manage/create. Default core.login.api is Super User only. Not Super User.
- Published
- 12 Oct 2026
- Updated
- 12 Oct 2026
- Tags
- 0-day, joomla, privilege-leftover, menus, cwe-863, authenticated
main is locked in the UI. the API did not get the key.
I am @abraxas_null. The proof of concept is on GitHub: abraxas/joomla-menu-items-api (loopback client). The lab stack is lab/: docker-compose.yml, run.sh, poc.py. Authorized lab only. It talks to loopback.
This is Joomla CMS 6.1.3 (0f2d4de4729eb951e0878fec98c7990da07915b2). No CVE yet. CWE-863. 8.1 High (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N). Remote privilege leftover. API token. Not Super User. Not installer RCE.
The administrator item controller checks com_menus.menu.{menutypeId} and blocks menutype == main. The API items controller does not override allowAdd / allowEdit. Default ApiController only checks component core.manage plus core.create / core.edit. A token user who may manage one menu can POST onto a menu they are denied in the UI, including the protected administrator main menu. That is enough to plant a URL, hide a real admin item, or point staff at a lookalike login. They still cannot install extensions unless they already have that permission.
Same pin: levels API, media override, articles catid.
Why Joomla
Same 6.1.3 hunt as the levels leftover. Webservices ACL was the bucket. UI controllers in this tree are often stricter than ApiController. When they are, the leftover is "the API forgot the asset the form already checks."
Pinning 6.1.3
Tag 6.1.3, 0f2d4de4729eb951e0878fec98c7990da07915b2. Image joomla:6.1.3-php8.3-apache. I read administrator ItemController next to api/.../ItemsController.php because Groups had already shown the pattern: UI gate, API miss, copy the allow* methods.
The skip list is half the hunt
- CVE-2026-73337 MFA captive allowlist. Closed.
- CVE-2026-73373 SHTML. Closed.
- CVE-2026-71574 mutating webservice
core.manage. Closed. That SA is component manage, not per-menutype. - Groups
core.admin. Closed. Untouched by this leftover. - CVE-2026-48947 webservice media override. Different controller.
- CORS / download headers. 6.1.3 complete.
I did not re-file any of those.
Surfaces that returned nothing
UI add/save on staffmenu for the lab Manager: "not permitted." UI add on labmenu still works. That is the per-menutype asset doing its job in administrator. Groups API core.admin stayed 403. Stock Manager without core.login.api cannot call the webservice.
Batch copy/move in the administrator model already check the menu asset. canSave on the item model only checks component core.edit. The API never reaches a per-menutype allowAdd.
No unpublished unauthenticated RCE. No installer leftover in this pack.
The leftover
ItemsController.php has no allowAdd / allowEdit. ApiController.php 552-582: component core.manage plus core.create / core.edit.
Administrator ItemController.php 43-91:
return $user->authorise('core.create', 'com_menus.menu.' . $menutypeID);if ($item->menutype == 'main') {
return false;
}
return $user->authorise('core.edit', 'com_menus.menu.' . (int) $menutypeID);main is the protected administrator navigation menutype. The UI refuses it on purpose. The API does not ask.
What an attacker can do
Token user who may create items on menu A only. They do not become Super User from this leftover.
Class: Privilege leftover. Reach: Remote.
| Privilege | Method / path | Kind | Lab-proven or inferred |
|---|---|---|---|
| Create an item on a menu they are denied | POST /api/index.php/v1/menus/administrator/items with menutype of B |
integrity | Lab-proven. HTTP 200, item 102 on staffmenu, title poc-JOOMLA-MENU-ITEMS-API-WITNESS |
Plant a URL on the protected administrator main menu |
Same POST with menutype=main |
integrity | Lab-proven HTTP 200. UI allowEdit returns false for main |
| Point staff at a lookalike login or hide a real admin item | Published URL item on an admin menu | integrity / recon | Inferred from the write. Lab planted https://example.invalid/ |
| Edit or delete items on menus they do not own | API PATCH / DELETE uses the same missing allow* |
integrity | Inferred. Lab exercised create |
| Install extensions or become Super User | Needs other ACL | n/a | Closed. Manager is not Super User |
Closed on this pin: UI add/save on staffmenu for the same user. UI add on labmenu still works. Groups API core.admin gate from 6.1.1 is untouched.
The lab
Loopback 127.0.0.1:19530. Manager group 6 had create on labmenu and an explicit deny on staffmenu. POST /api/index.php/v1/menus/administrator/items with menutype=staffmenu returned 200 and stored item 102 titled JOOMLA-MENU-ITEMS-API-WITNESS. The same call with menutype=main also returned 200. The same user in administrator got "not permitted" on add and save for staffmenu, and could still open add for labmenu.
SUCCESS joomla-menu-items-api api-b-http=200 item-id=102 menutype=staffmenu api-main-http=200 ui-add-b=200 ui-save-b=200 JOOMLA-MENU-ITEMS-API-WITNESSui-add-b / ui-save-b are HTTP 200. Denial of B is the UI "not permitted" body, not a 403 status.
python3 joomla-menu-items-api-Abraxas-Labs.pyor cd lab && ./run.sh. Loopback only.
Wrong turns, in order
I read UI HTTP 200 as allow. Joomla administrator often returns 200 with a "not permitted" flash. The body is the oracle, not the status.
I treated core.manage on com_menus as enough in the UI. The UI still keys off com_menus.menu.{id}. Manage is how you open the component. Create is per menu type.
I hit the API as a stock Manager. Default core.login.api is Super User only. Grant it first, same as the 2026 webservice series.
Theatre: a reverse shell. The oracle is API 200 on staffmenu and main plus UI denial on B.
The fix
Copy ItemController::allowAdd / allowEdit (and delete) onto the API controller, including the main block. Check the menu-type asset in canSave the same way.
Pack
- GitHub: abraxas/joomla-menu-items-api
- Loopback client: joomla-menu-items-api-Abraxas-Labs.py
- Lab: lab/
Abraxas Labs · abraxaslabs.tech · github.com/abraxas · @abraxas_null · abraxas.null@proton.me