Un usuario con rol cashier puede abrir cualquier pantalla de administración escribiendo la URL (/admin, /admin/usuarios, /admin/inventario/productos, etc.). apps/web/src/app/admin/_components/admin-shell.tsx solo revisa que haya sesión (if (!user) return null), no el rol, y no hay un proxy.ts que proteja las rutas.
Entorno
local
Módulos
Web / frontend, Auth / sesión / roles, Usuarios
Severidad
Bloquea un flujo
Pasos para reproducir
Iniciar sesión con un usuario cashier; la app lo manda a /pos.
Escribir /admin/usuarios en la barra de direcciones.
Crear, editar o borrar un usuario.
Esperado
Un cajero que entra a /admin/* es redirigido a /pos y no ve ni puede usar las pantallas de administración.
Actual
El cajero ve el panel completo y puede crear, editar o borrar usuarios, productos, precios, inventarios, proveedores y clientes.
Evidencia
Encontrado en auditoría de código; no reproducido en ejecución.
// admin-shell.tsx
const { user, logout}= useSessionUser();
...
if(!user)return null; // no se revisa user.role
Arreglo sugerido: redirigir a /pos cuando user.role !== "admin" en AdminShell, o en proxy.ts (en Next 16 la convención middleware está deprecada y se reemplazó por proxy). Esto solo protege la UI: el API sigue abierto hasta resolver #5.
¿Está también en producción?
Sí — este issue no basta; hay que abrir un Incidente / hotfix
No — solo local / staging
No sé
Antes de abrir
Busqué un issue duplicado
### Qué pasa
Un usuario con rol `cashier` puede abrir cualquier pantalla de administración escribiendo la URL (`/admin`, `/admin/usuarios`, `/admin/inventario/productos`, etc.). `apps/web/src/app/admin/_components/admin-shell.tsx` solo revisa que haya sesión (`if (!user) return null`), no el rol, y no hay un `proxy.ts` que proteja las rutas.
### Entorno
local
### Módulos
Web / frontend, Auth / sesión / roles, Usuarios
### Severidad
Bloquea un flujo
### Pasos para reproducir
1. Iniciar sesión con un usuario `cashier`; la app lo manda a `/pos`.
2. Escribir `/admin/usuarios` en la barra de direcciones.
3. Crear, editar o borrar un usuario.
### Esperado
Un cajero que entra a `/admin/*` es redirigido a `/pos` y no ve ni puede usar las pantallas de administración.
### Actual
El cajero ve el panel completo y puede crear, editar o borrar usuarios, productos, precios, inventarios, proveedores y clientes.
### Evidencia
```shell
Encontrado en auditoría de código; no reproducido en ejecución.
// admin-shell.tsx
const { user, logout } = useSessionUser();
...
if (!user) return null; // no se revisa user.role
```
Arreglo sugerido: redirigir a `/pos` cuando `user.role !== "admin"` en `AdminShell`, o en `proxy.ts` (en Next 16 la convención `middleware` está deprecada y se reemplazó por `proxy`). Esto solo protege la UI: el API sigue abierto hasta resolver #5.
### ¿Está también en producción?
- [ ] Sí — este issue no basta; hay que abrir un Incidente / hotfix
- [ ] No — solo local / staging
- [x] No sé
### Antes de abrir
- [x] Busqué un issue duplicado
Miguel
was assigned by Carlos2026-10-02 20:05:33 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Qué pasa
Un usuario con rol
cashierpuede abrir cualquier pantalla de administración escribiendo la URL (/admin,/admin/usuarios,/admin/inventario/productos, etc.).apps/web/src/app/admin/_components/admin-shell.tsxsolo revisa que haya sesión (if (!user) return null), no el rol, y no hay unproxy.tsque proteja las rutas.Entorno
local
Módulos
Web / frontend, Auth / sesión / roles, Usuarios
Severidad
Bloquea un flujo
Pasos para reproducir
cashier; la app lo manda a/pos./admin/usuariosen la barra de direcciones.Esperado
Un cajero que entra a
/admin/*es redirigido a/posy no ve ni puede usar las pantallas de administración.Actual
El cajero ve el panel completo y puede crear, editar o borrar usuarios, productos, precios, inventarios, proveedores y clientes.
Evidencia
Arreglo sugerido: redirigir a
/poscuandouser.role !== "admin"enAdminShell, o enproxy.ts(en Next 16 la convenciónmiddlewareestá deprecada y se reemplazó porproxy). Esto solo protege la UI: el API sigue abierto hasta resolver #5.¿Está también en producción?
Antes de abrir