Area: Admin deep-dive (commerce/config) (audit p15b) · Surface: POST /admin/knowledge/ai/outline (Admin\AdminAIController@wikiOutline) · Dimension: security · Severity: minor
wikiOutline declares requireRole(2) (Registered user) as its in-controller gate, inconsistent with the role-3/role-4 floor used by every other handler in the class. It is not currently exploitable because the route lives under the /admin group whose AdminMiddleware raises the effective floor to role 3, but the controller-level defense-in-depth (which CLAUDE.md mandates: 'requireRole(N) at the top of every admin handler ... on top of AdminMiddleware') is set too low. If this handler were ever re-registered outside the /admin group, a role-2 user could invoke a billable AI endpoint that consumes the tenant's Anthropic spend. OWASP A01:2021 (Broken Access Control), defense-in-depth.
Evidence
platform/src/Controllers/Admin/AdminAIController.php:57-65 `public function wikiOutline(): void { $this->requireRole(2); ... }` while every other handler in the same controller uses requireRole(3) or requireRole(4) (e.g. wikiSuggestEdits uses requireRole(3) at line 86, wikiStale uses requireRole(4) at line 69). The route is registered inside the /admin group (routes.php:1635 within the `$router->group('/admin', [AuthMiddleware, AdminMiddleware, ...])` block starting at routes.php:1479), and AdminMiddleware enforces role >= 3 (platform/src/Middleware/AdminMiddleware.php: `if (!$user || (int) $user['role'] < 3)`).
Suggested fix. Raise wikiOutline to requireRole(3) (or 4) to match the other AI handlers in the controller and the documented admin-handler convention.
Filed by the automated tenant-app audit and adversarially evidence-verified. Status: verified. Open — not yet actioned.
Patrick Bass
@mobieus