CreaRack-SL

Mega-auditoría T02 (24-09-2026): la gestión de usuarios sin las reglas de la API, sin candado ante superiores y sin rastro

Cuándo

24-09-2026, PR #592, commit 59be81cd. Segunda tanda (T02) de la mega-auditoría del 24-09-2026 sobre gestión de usuarios; publicada como v1.154.0.

Síntomas visibles

Ningún incidente reportado por clientes — son hallazgos de auditoría interna. Seis huecos de seguridad en la superficie de gestión de usuarios (API Ninja + vistas HTMX):

  • El alta HTMX (POST /htmx/users/create) guardaba el rol tal cual llegaba del formulario, sin validarlo contra VALID_ROLES ni contra el nivel de quien lo creaba (B-05, D1-01).
  • Dos rutas HTMX de edición (GET /htmx/users/<id>/edit, PUT /htmx/users/<id>) seguían vivas sin que ninguna plantilla ni JS las llamara, y dejaban cambiar rol/contraseña de cualquier usuario de la organización, superusuarios incluidos (D1-02).
  • La única protección contra tocar a alguien “por encima” comprobaba is_superuser/is_staff, pero no el nivel de permisos por módulo: un operador con override users:admin podía resetear la contraseña de un admin normal y entrar como él (B-28).
  • Crear, editar, borrar un usuario o quitarle el MFA no dejaba ningún rastro en el registro del sistema (B-32).
  • Varias vistas HTMX de solo lectura (listado/búsqueda de racks, nombre inline, mapas, papelera de racks/mapas/dispositivos, grupos) solo exigían sesión iniciada, no el permiso de ver ese módulo (B-63).

Causa raíz

Las reglas de “quién puede tocar a quién” vivían duplicadas: la API Ninja las tenía a medias (sin comparar niveles de permiso) y las vistas HTMX reimplementaban su propia copia, más vieja y más floja. Las rutas de edición HTMX quedaron huérfanas tras mover ese flujo al modal de base.html (que ya llama a la API), pero nadie las borró. Ninguna de las dos capas escribía en el registro de auditoría para acciones sobre usuarios.

Fix aplicado (commit 59be81cd, PR #592)

  • Nueva función única target_outranks_actor(actor, target) en core/api/users.py: compara el nivel efectivo de permisos de target contra el de actor en cada scope (además del caso superuser/staff) y bloquea si el objetivo está por encima en cualquiera. La usan tanto la API (update_user, delete_user, delete_user_mfa_device) como las vistas HTMX, vía el helper _deny_target.
  • POST /htmx/users/create valida ahora role in VALID_ROLES y _role_exceeds_grantor, igual que POST /api/users/.
  • Retiradas user_edit_form y user_update de core/htmx_views.py, sus rutas en core/htmx_urls.py y la plantilla templates/htmx/users/edit_form.html.
  • log_action (categoría AUTH) en user.create, user.update, user.delete, user.mfa_remove y user.mfa_remove_all, por API y por HTMX, sin registrar la contraseña (solo que cambió).
  • Gate has_permission(request.user, <scope>, "view") añadido a las vistas HTMX de solo lectura de racks, mapas, papelera y grupos.
  • Cobertura: tests/api/test_mega_t02.py (255 líneas nuevas).

Lecciones

  • Una regla de “quién manda sobre quién” que vive en dos sitios (API y HTMX) tiende a divergir: la copia más vieja se queda sin el refinamiento que recibe la otra. Unificarla en una función que llaman ambas capas es lo que impide que reaparezca.
  • Una ruta sin llamador conocido no es inofensiva: mientras exista, sigue expuesta. D1-02 solo salió a la luz auditando, no por un fallo reportado.

Preventivos futuros

  • Al mover un flujo de HTMX a la API (o viceversa), borrar la ruta vieja en el mismo cambio, no dejarla “por si acaso”.
  • Toda acción que cambie o borre un usuario (o le quite un factor de MFA) pasa por log_action; si se añade un mutador nuevo sobre User, este es el patrón a copiar.
  • Límite honesto: el rastro va en la categoría AUTH porque una categoría USERS dedicada exigiría migración; fuera de alcance de esta tanda. El logo y los datos de empresa (core/api/settings.py) tampoco dejan rastro todavía.

Véase también

  • [[entity—core—service—has-permission]]
  • [[entity—core—service—log-action]]
  • [[decision—20260607—audit-logs-best-effort]]
  • [[feature—security—auditoria-suprema-2-tanda-1-core]]
  • [[incident—20260602—auditoria-suprema-mini-tanda-seguridad]]
  • [[crearack—conceptos—usuarios-y-permisos]]
  • [[crearack—settings—user-management]]