Security: Privilege escalation via role permissions (create_role/update_role) #75

Closed
opened 2026-07-08 02:37:03 +00:00 by icub3d · 0 comments
Owner

Severity: Critical — found in code review 2026-07-07.

Problem

create_role (server/src/roles/handlers.rs:121) and update_role (:162) pass req.permissions straight to storage without checking that the caller actually holds those bits. They gate only on MANAGE_ROLES and role position.

A user with MANAGE_ROLES but not ADMINISTRATOR can:

  1. POST /roles with permissions = ADMINISTRATOR (1<<13) and position = highest_role_position - 1 (passes the position check).
  2. PUT /members/{self}/roles/{new_role}add_member_role only checks ensure_higher_than(role.position), which passes.
  3. Re-issue any request → compute_base_permissions ORs in ADMINISTRATOR → full server control.

update_role has the same hole — it blocks editing the built-in admin role's permissions but allows adding ADMINISTRATOR to any other lower-positioned role.

Impact: any MANAGE_ROLES holder escalates to full admin. Collapses the entire permission model.

Fix

When the caller lacks ADMINISTRATOR, reject any req.permissions containing bits the caller doesn't hold: (req.permissions & !caller.permissions) != 0 → 403. Specifically forbid setting ADMINISTRATOR. Apply to both create_role and update_role.

Acceptance

  • create_role rejects permission bits the caller doesn't hold (403)
  • update_role rejects permission bits the caller doesn't hold (403)
  • Regression test: a MANAGE_ROLES-only user gets 403 minting an ADMINISTRATOR role
**Severity: Critical** — found in code review 2026-07-07. ## Problem `create_role` (`server/src/roles/handlers.rs:121`) and `update_role` (`:162`) pass `req.permissions` straight to storage without checking that the caller actually holds those bits. They gate only on `MANAGE_ROLES` and role *position*. A user with `MANAGE_ROLES` but **not** `ADMINISTRATOR` can: 1. `POST /roles` with `permissions = ADMINISTRATOR` (`1<<13`) and `position = highest_role_position - 1` (passes the position check). 2. `PUT /members/{self}/roles/{new_role}` — `add_member_role` only checks `ensure_higher_than(role.position)`, which passes. 3. Re-issue any request → `compute_base_permissions` ORs in `ADMINISTRATOR` → full server control. `update_role` has the same hole — it blocks editing the built-in `admin` role's permissions but allows adding `ADMINISTRATOR` to any other lower-positioned role. **Impact:** any `MANAGE_ROLES` holder escalates to full admin. Collapses the entire permission model. ## Fix When the caller lacks `ADMINISTRATOR`, reject any `req.permissions` containing bits the caller doesn't hold: `(req.permissions & !caller.permissions) != 0` → 403. Specifically forbid setting `ADMINISTRATOR`. Apply to **both** `create_role` and `update_role`. ## Acceptance - [ ] `create_role` rejects permission bits the caller doesn't hold (403) - [ ] `update_role` rejects permission bits the caller doesn't hold (403) - [ ] Regression test: a `MANAGE_ROLES`-only user gets 403 minting an `ADMINISTRATOR` role
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
icub3d/decentcom#75
No description provided.