Bugs de autorización en apps CRUD: audita roles, tenants y rutas
Aprende a detectar y corregir bugs de autorización en apps CRUD auditando checks de roles, scoping de tenant y rutas API antes de que los usuarios accedan a datos de otros.

Por qué los usuarios terminan viendo datos de otros
Un bug de autorización ocurre cuando tu app permite que la persona equivocada acceda a algo aunque esté autenticada. Eso es distinto de la autenticación, que solo prueba quién es alguien (inicio de sesión, contraseña, enlace mágico). La autorización responde a otra pregunta: ahora que estás dentro, ¿qué puedes hacer y qué registros son tuyos?
Cuando la autorización falla aunque sea un poco, las consecuencias raramente son pequeñas. Un usuario podría ver facturas de otro cliente, editar el perfil de otra persona o eliminar registros que ni siquiera debería conocer. En apps CRUD esto es especialmente peligroso porque todo puede verse normal en la UI hasta que alguien cambia una URL, modifica una petición en el navegador o llama a una ruta API sin protección.
Esto aparece mucho en dashboards, paneles de administración y portales de clientes. Estas apps crecen rápido: nuevas pantallas, nuevos endpoints, nuevos filtros. Un filtro de tenant faltante en una consulta de tabla y de pronto aparecen registros de otra cuenta.
Un patrón común detrás de estos bugs es el privilege creep. Los permisos se expanden con el tiempo. Comienzas con “los usuarios ven sus cosas”, luego añades herramientas de soporte, luego una vista de admin, luego un endpoint de exportación. Cada paso añade un nuevo lugar donde las comprobaciones pueden desviarse.
Un ejemplo realista: un portal de clientes tiene un botón “Descargar recibo”. El endpoint recibe un receipt ID. Si el servidor solo comprueba “el usuario está autenticado” pero no “el recibo pertenece a este tenant”, un usuario puede adivinar o reutilizar un ID y descargar el recibo de otra persona.
Estos errores sobreviven porque falta uno de los básicos:
- una regla clara de propiedad (usuario, equipo o tenant)
- comprobaciones consistentes en cada lectura y escritura
- tests que intenten explícitamente acceso entre cuentas
Los equipos suelen encontrarse con esto en prototipos generados por IA. La autenticación funciona, pero las reglas de autorización no se aplican de forma consistente en rutas y consultas. Ahí es cuando “funcionó en la demo” se convierte en una fuga de datos en producción.
Roles, permisos y tenants - un modelo simple
La mayoría de las fugas de datos ocurren porque la app no está de acuerdo en una pregunta simple: ¿quién es este usuario y qué puede hacer ahora?
Empieza por nombrar las piezas de identidad que tu app debería llevar en cada petición:
- User ID: la persona que hace la petición.
- Role: el tipo de acceso que tiene (viewer, editor, admin).
- Tenant ID: la organización/workspace/proyecto al que pertenece.
Un chequeo de rol responde “¿puedes hacer esta acción?” El scoping por tenant responde “¿sobre qué registros puedes actuar?” Normalmente necesitas ambos.
Por ejemplo, role = editor podría permitir “editar facturas”. Pero sin scoping por tenant, una consulta como “update invoice by id” puede actualizar una factura en otro workspace. El usuario tenía permiso, pero no para ese tenant.
Chequeos de rol vs scoping de tenant
Los chequeos de rol suelen ser sencillos: ¿puede este usuario borrar?, ¿invitar compañeros?, ¿acceder a la pantalla de facturación? El scoping por tenant es la valla que mantiene cada lectura y escritura dentro de la organización/workspace correcto.
Una forma rápida de recordarlo:
- Role decide qué puedes hacer.
- Tenant decide dónde puedes hacerlo.
La trampa del “admin"
“Admin” es donde muchas apps se vuelven descuidadas. Hay una gran diferencia entre:
- Tenant admin: puede gestionar usuarios y ajustes dentro de su propio workspace.
- Global admin: puede acceder a todo a través de todos los tenants (raro, normalmente personal interno).
Si tu código trata cualquier admin como global, un admin normal de cliente puede acabar viendo datos de otros clientes. Esto es especialmente común cuando “admin” se implementa como una sola bandera sin aclarar el alcance.
Una advertencia más: las restricciones solo en la UI no son seguridad. Ocultar botones ayuda en la usabilidad, pero no protege datos. Si una ruta API acepta una petición, un usuario aún puede llamarla directamente, aunque la UI nunca muestre la opción.
Dónde debe aplicarse la autorización
La autorización no es una única comprobación que añades “en algún lugar del backend”. En la mayoría de las fugas, el equipo sí tenía una comprobación, pero vivía en el lugar equivocado o solo cubría una capa.
Piensa en la aplicación de reglas como una pila. Cada capa bloquea un tipo diferente de error, especialmente en código construido rápido donde los handlers se copian y editan.
Piensa en capas (no en una sola guardia)
Empieza en el borde, donde las peticiones entran al sistema. Si un endpoint no debería ser invocable por un rol, bloquéalo antes de que ocurra cualquier trabajo. Eso previene problemas de “puedo golpear la URL directamente”.
Luego, aplica control sobre el registro específico. No basta con saber que alguien está autenticado. Debes probar que el registro pertenece a su tenant (o que tiene una razón válida cross-tenant, como un rol de soporte interno).
Finalmente, controla qué pueden ver o cambiar dentro de ese registro. Muchas apps limitan qué filas se devuelven pero aún filtran campos sensibles (notas internas) o aceptan cambios en campos propiedad del servidor (role, plan, tenantId).
Una forma práctica de ubicar las comprobaciones:
- Acceso a la ruta: quién puede llamar este endpoint en absoluto
- Acceso al registro: qué item(s) específicos pueden leer o modificar
- Acceso a la acción: qué pueden hacer (leer vs editar vs borrar vs exportar)
- Acceso a campos: qué propiedades se devuelven o se aceptan
Una regla que atrapa la mayoría de fugas
Asume que los clientes no son de confianza, incluso tu propio frontend. Si una petición incluye un ID, un tenantId o un role, trátalo como una pista, no como hecho. El servidor debe derivar la identidad y el tenant desde la sesión o el token, y luego aplicar eso a cada consulta y escritura.
Al revisar código, busca lugares donde solo exista una capa. Si cualquier ruta devuelve datos, pregunta: ¿aplicamos acceso en la ruta, registro, acción y campo, o solo en una y esperamos que cubra lo demás?
Empieza con un mapa de permisos que puedas seguir
La mayoría de los errores de autorización empiezan como un problema documental. Nadie puede responder, en un solo lugar, “¿quién puede hacer qué sobre qué registros?” Así que las comprobaciones se añaden ad hoc, las rutas derivan y el privilege creep aparece.
Un mapa de permisos es una referencia en lenguaje claro que puedes tener abierta mientras auditas rutas y consultas. Mantenlo lo bastante pequeño para que un compañero no técnico pueda leerlo y detectar una regla extraña.
1) Escribe la tabla roles→acciones (sin jerga)
Empieza con los roles que realmente tienes en producción, no los que planeas tener. Luego mapea esos roles a acciones usando verbos simples: ver, crear, editar, borrar, invitar, exportar, cambiar facturación.
| Role | Puede ver | Puede crear | Puede editar | Puede borrar | Puede gestionar usuarios |
|---|---|---|---|---|---|
| Member | Sus items | Sí | Sus items | No | No |
| Manager | Items de la org | Sí | Items de la org | Limitado | Invitar miembros |
| Admin | Items de la org | Sí | Items de la org | Sí | Completo |
Si no puedes describir una regla sin excepciones, es una señal de que necesitas otro rol o un concepto adicional como “owner”.
2) Marca cada frontera de tenant y la clave que la delimita
Muchas apps tienen más de una frontera: account, org, workspace, project. Anótalas y elige la clave que las escapa (por ejemplo, org_id o workspace_id). Luego lista cada recurso y la clave de tenant que siempre debe estar presente.
Cuando hagas esto, céntrate en tres preguntas:
- ¿Qué scopeea cada recurso (org_id, workspace_id, project_id)?
- ¿De dónde viene ese scope (sesión, token, URL, body)?
- ¿Qué fronteras nunca se pueden cruzar?
Finalmente, define “owner” por recurso. Owner no es universal. Un comentario puede ser propiedad de su creador, una tarea del asignado, una factura de la cuenta.
Un ejemplo concreto: si “owner” de un documento significa “creador”, entonces un manager no debería editar automáticamente todos los documentos a menos que tu tabla diga que los managers pueden editar todos los documentos de la org. Este detalle evita un error común: usar checks de rol para saltarse el scoping por tenant.
Auditoría paso a paso: rutas API y handlers del servidor
Los bugs de autorización suelen esconderse en lugares aburridos: las rutas que olvidaste que existían, el handler que “solo actualiza un registro”, o el endpoint de admin que nunca recibió comprobaciones reales. Una auditoría es, en gran medida, inventario más disciplina.
1) Lista todas las rutas (sí, todas)
Enumera cada ruta API que expone tu app, incluidos endpoints internos, de admin y los “temporales” añadidos durante prototipos. Estos experimentos suelen quedarse y seguir accesibles.
Elige una fuente de verdad (tu archivo de router, la carpeta de routes del framework o la configuración del API gateway) y crea una tabla simple. Si encuentras rutas que ya no se usan, márcalas para eliminación, pero audítalas primero.
2) Para cada ruta, escribe: actor, acción, recurso, frontera de tenant
Para cada ruta escribe una frase en inglés sencillo:
- Actor: ¿quién llama? (usuario autenticado, admin de org, job del sistema)
- Acción: ¿qué hacen? (leer, crear, actualizar, borrar)
- Recurso: ¿qué objeto toca? (invoice, project, user, file)
- Frontera de tenant: ¿qué contenedor debe coincidir? (org_id, workspace_id, account_id)
Si no puedes describir la regla en una frase, el código suele ser inconsistente.
3) Verifica el scope de tenant en el servidor, no en el cliente
Comprueba que el handler deriva el tenant desde la sesión autenticada (o los claims del token del servidor), no desde campos del body o query params.
Una señal de alarma común: la petición incluye orgId y el servidor la toma como verdadera. Un patrón más seguro es: leer org_id desde la sesión del usuario y luego aplicarlo en cada consulta y mutación.
4) Confirma que las escrituras también están scopeadas (no solo las lecturas)
Los equipos suelen scopear las páginas de lista pero olvidan los updates y deletes. Busca endpoints como:
PATCH /projects/:idDELETE /invoices/:idPOST /members/:id/role
Si el handler actualiza solo por id, es un riesgo de cross-tenant inmediato. La comprobación debe ser: “registro con este id Y este tenant pertenece a este actor”.
5) Vigila rutas que aceptan IDs y traen registros “a pelo”
Cualquier ruta que reciba un id es un punto caliente. El patrón peligroso es:
- buscar por
id - comprobar algo de forma laxa (o no comprobar)
- devolver o mutar
En su lugar, integra la autorización como parte de la búsqueda. Si el registro no está en el tenant del actor (o el actor no tiene permiso), la búsqueda debe fallar.
Auditoría paso a paso: consultas a DB y filtros del ORM
La autorización puede parecer correcta en el controlador y luego romperse en la capa de base de datos. Si una consulta puede devolver registros de otro tenant, la app eventualmente los mostrará, quizá en búsquedas, exportaciones o casos límite que no probaste.
Empieza encontrando cada lugar donde la app lee “muchas filas” (páginas de lista, búsqueda, tablas de admin, jobs en background). Para cada consulta, pregúntate: ¿dónde se aplica el filtro de tenant y se puede omitir?
1) Audita consultas de listas (muchas filas)
Abre cada endpoint de lista y tráelo hasta la llamada al ORM. Las restricciones de tenant deben formar parte de la consulta cada vez, no añadirse después en memoria.
Una checklist que atrapa la mayoría de fugas:
- El scope de tenant está en la consulta a la base de datos (no filtrado tras la carga).
- La paginación usa la misma consulta scopeada (la consulta de count y la de datos coinciden).
- Los términos de búsqueda se combinan con el scope de tenant usando AND, no OR.
- La lógica de sort y cursor no puede recurrir a una consulta base sin scope.
- “Incluir datos relacionados” no carga hijos de otro tenant.
2) Audita consultas de detalle (fila única)
Los endpoints de detalle nunca deberían buscar solo por id. La búsqueda debe incluir tenantId e id (u otra clave única ligada al tenant). Si tu ORM tiene helpers como findUnique(id), trátalos con sospecha a menos que la clave única incluya tenantId.
Prefiere “findFirst where tenantId = X and id = Y” en lugar de “find by id y luego comprobar tenant”. El segundo patrón es fácil de olvidar en un handler.
3) Joins, exportaciones y consultas “especiales”
Los joins son un lugar común donde el scoping por tenant desaparece. Una consulta puede empezar scopeada y luego hacer un join a otra tabla y filtrar por el campo de tenant equivocado (o no filtrar).
También revisa reportes, exportaciones y jobs en background. Estos a menudo evaden el código normal de la API, así que necesitan las mismas reglas de scoping a nivel de consulta.
Trampas comunes que causan privilege creep
El privilege creep rara vez ocurre porque alguien escribió “permitir todo”. Sucede porque pequeños atajos se acumulan: una ruta confía en la UI, otra asume que “admin” es global, una tercera olvida un job.
Error 1: Confiar en el cliente (flags en UI, botones ocultos)
Si un usuario puede editar una petición, puede editar cualquier cosa que envíe el navegador. Un botón “Eliminar” oculto o un flag client-side role: "admin" no es protección. El servidor debe decidir basándose en la identidad autenticada.
Una versión común: la UI oculta “Editar factura” a menos que seas manager, pero la ruta API solo comprueba que estás autenticado. Cualquiera puede llamar la ruta directamente y actualizar la factura de otro.
Error 2: Usar “isAdmin” sin scope de tenant
“Admin” no tiene sentido si no dices: ¿admin de qué? En apps multi-tenant, la mayoría de los roles deben estar scopeados por tenant. La trampa es escribir lógica tipo “if isAdmin, allow” y conceder acceso entre tenants por accidente.
Un chequeo mental más seguro: cada decisión de autorización debería responder dos preguntas, “¿quién es este usuario?” y “¿a qué tenant pertenece este dato?” Si alguna respuesta es imprecisa, estás a un refactor de acceso cross-tenant.
Error 3: Comprobar después de cargar el registro
Muchas fugas ocurren porque el código obtiene primero el registro y luego comprueba si el usuario puede verlo. Aunque bloquees la respuesta, aún puedes filtrar por mensajes de error distintos (404 vs 403), diferencias de tiempo o datos relacionados cargados en el proceso.
Prefiere comprobaciones que impidan la recuperación del registro incluyendo las reglas de tenant y propiedad directamente en la consulta.
Error 4: Olvidar “puertas laterales” (jobs, webhooks, descargas)
Jobs en background, tareas cron, handlers de webhooks y endpoints de descarga de archivos suelen saltarse el middleware habitual y acabar con comprobaciones más débiles. Si un job procesa “todas las facturas” sin filtro de tenant, puede enviar por email o exportar datos de clientes equivocados.
Para estas rutas, asegúrate de poder responder: ¿autentica al llamante (o valida el webhook)?, ¿aplica scoping por tenant en cada consulta?, ¿registra lo que tocó (tenant id, record id, actor)?
Error 5: Helpers compartidos con defaults poco claros
Un helper como getUserProjects(userId) suena seguro hasta que alguien lo reutiliza en una pantalla de admin y asume que devuelve “todos los proyectos”. O peor, un helper por defecto “no aplica filtro de tenant” cuando falta tenantId.
Los buenos helpers fallan con contundencia. Si tenantId es requerido por seguridad, hazlo obligatorio en la firma de la función y lanza un error si falta.
Un ejemplo realista: una ruta mala, una fuga grande
Imagina que tienes un rol Support Agent. Deberían poder ver tickets de soporte, pero solo de su propia organización (su tenant). Suena simple, pero basta un endpoint descuidado para romper la regla.
Aquí está la equivocación: la API tiene una ruta como GET /api/tickets/:ticketId. El handler comprueba que el usuario está autenticado, luego obtiene el ticket por ID. Nunca comprueba el tenant.
// Unsafe: fetches by ID only
const ticket = await db.ticket.findUnique({
where: { id: ticketId }
});
return ticket;
Por qué esto filtra datos: los ticket IDs muchas veces aparecen en lugares accesibles, como URLs del navegador, notificaciones por email, logs de herramientas de soporte o CSVs exportados. Incluso sin eso, muchas apps usan IDs previsibles (números incrementales, UUIDs cortos copiados de la UI). Un usuario curioso o malicioso puede intercambiar un ID y ver un ticket de otra org.
Ese es uno de los fallos más comunes: el código asume que conocer un ID es prueba de que debes ver el registro.
Un handler más seguro hace dos cosas distintas:
- Aplica el scope de tenant en la consulta usando la org de la sesión.
- Comprueba el rol para la acción (ver el ticket).
// Safer: enforce role + tenant scoping
if (user.role !== "support_agent") throw new Error("Forbidden");
const ticket = await db.ticket.findFirst({
where: { id: ticketId, orgId: user.orgId }
});
if (!ticket) throw new Error("Not found");
return ticket;
Fíjate en el comportamiento “Not found”. Evita confirmar que un ticket existe en otra org.
Para verificar el arreglo, mantén el test simple:
- Crea dos orgs, Org A y Org B.
- Crea un ticket en Org B.
- Inicia sesión como Support Agent en Org A.
- Llama al endpoint usando el
ticketIdde Org B. - Confirma que obtienes “Not found” (o 404) y que no se devuelve ningún dato del ticket.
Comprobaciones rápidas que puedes correr antes de una release
La mayoría de los bugs de autorización aparecen en la última milla: una ruta nueva, un atajo de admin “útil” o una consulta que olvidó el scoping. Estas comprobaciones son sencillas y repetibles.
La prueba de humo de dos cuentas (10 minutos)
Crea dos cuentas de prueba que parezcan normales pero pertenezcan a tenants distintos (Compañía A y Compañía B). Dales datos realistas para que puedas distinguir qué pertenece a quién.
Luego mezcla intencionadamente identificadores:
- Copia un ID de registro de Tenant A y trata de leerlo desde Tenant B.
- Intenta actualizar con el ID de Tenant A estando autenticado como Tenant B.
- Intenta borrar con el ID de Tenant A desde Tenant B.
- Si tu app usa soft delete, prueba restaurar/undelete también.
- Repite para objetos hijos (comentarios, facturas, archivos) que puedan tener scopes distintos.
Si alguna de estas acciones tiene éxito o devuelve datos reales, probablemente te faltan filtros de tenant o hay un check de rol que solo corre en la UI.
No olvides funciones en bloque y puertas traseras
Las fugas suelen suceder fuera de las pantallas CRUD principales. Un endpoint de lista puede estar scopeado, pero la exportación no. Una descarga de archivo puede saltarse comprobaciones porque es “solo una URL”.
Haz un repaso rápido de:
- Páginas de lista con filtros, búsqueda, orden y paginación (prueba buscando un valor conocido del otro tenant).
- Endpoints de exportación (CSV, PDF, reportes) y jobs en background que los generan.
- Descargas y previews de archivos (signed URLs, attachment IDs, endpoints de imagen).
- Logs de actividad, dashboards de admin y widgets de “items recientes”.
- Cualquier ruta que acepte un ID en la path, incluso si la UI nunca lo expone.
También confirma que tus roles de admin están scopeados como pretendes. “Tenant admin” no debería comportarse como “global admin” por conveniencia.
Próximos pasos: hacer que la autorización sea difícil de romper
Los fallos de autorización rara vez ocurren porque a la gente no le importe. Ocurren porque las comprobaciones están dispersas, los filtros de tenant son fáciles de olvidar y las nuevas funciones se lanzan más rápido de lo que las reglas se actualizan. El objetivo es hacer que la ruta segura sea la más fácil.
Pon una valla delante de todo
Usa una capa de autorización consistente en todas partes: middleware, un helper de políticas o un servicio que cada handler llame antes de hacer trabajo. Si tienes que recordar qué rutas “necesitan checks”, olvidarás alguna.
Una regla práctica: los handlers de rutas no deberían contener lógica de permisos personalizada. Deberían preguntar a una capa de políticas una pregunta clara (por ejemplo, “¿puede este usuario actualizar esta factura?”) y luego continuar.
Cambios que reducen errores rápidamente:
- Crea un helper de políticas (o middleware) por recurso: read, create, update, delete.
- Haz que el scoping por tenant sea el comportamiento por defecto (por ejemplo, un helper de consultas que siempre aplica tenantId).
- Deniega por defecto cuando falte o sea ambigua la información (sin tenant, sin role, sin ownership).
- Registra denegaciones de autorización con contexto suficiente para depurar (usuario, tenant, recurso, acción).
Incorpora el scoping por tenant en el acceso a datos
Centraliza el scoping por tenant para que sea difícil olvidarlo. El mejor lugar es donde se construyen las consultas, no donde se devuelven las respuestas.
Por ejemplo, en lugar de escribir where: { id } en muchos lugares, expón un helper que ya incluya tenantId. Si un desarrollador intenta evitarlo, debería notarse en la revisión de código.
Los tests de alto valor detectan regresiones que importan realmente:
- Lectura cross-tenant falla (Usuario A no puede obtener el registro de Usuario B por ID).
- Escritura cross-tenant falla (Usuario A no puede actualizar/borrar el registro de Usuario B).
- Downgrade de rol es seguro (un usuario que pierde derechos de admin no mantiene acceso de admin).
- La creación está scopeada (los registros nuevos se sellan con el tenant actual).
Si heredaste una codebase generada por IA y no confías en que el scoping de tenant y los checks de rol se apliquen de forma consistente, una auditoría focalizada puede ahorrarte días de conjeturas. FixMyMess (fixmymess.ai) se especializa en diagnosticar y reparar este tipo de brechas de autorización, especialmente los handlers “solo id” y las consultas sin scope que parecen correctas hasta que usuarios reales llegan a producción.
Preguntas Frecuentes
¿Por qué pueden los usuarios ver datos de otra persona aunque el inicio de sesión funcione?
Es un problema de autorización, no de autenticación. Pueden estar completamente autenticados, pero tu servidor no está demostrando de forma consistente que el registro que solicitan pertenece a su usuario/equipo/tenant antes de devolverlo.
¿Cuál es la diferencia entre autenticación y autorización?
La autenticación responde “¿quién eres?” La autorización responde “¿qué puedes hacer y qué registros son tuyos?” La mayoría de las filtraciones entre cuentas ocurren cuando las apps solo comprueban que el usuario está firmado y luego obtienen datos por ID sin verificar propiedad o ámbito de tenant.
¿Necesito checks de rol, scoping de tenant, o ambos?
Los checks de rol deciden qué acciones puede realizar un usuario (por ejemplo, “editar facturas”). El scope por tenant decide dónde pueden ejecutar esas acciones (por ejemplo, “solo dentro de este workspace”). Normalmente necesitas ambos: un usuario puede tener el rol correcto pero apuntar a los registros del tenant equivocado.
¿Qué endpoints son los que más probablemente filtren datos entre tenants?
Cualquier endpoint que acepte un id es un punto caliente, especialmente descargas, exportaciones y rutas de detalle. Si el handler busca un registro solo por id, un usuario puede intercambiar IDs y potencialmente acceder a datos de otro tenant.
Si la UI oculta funciones de admin, ¿es eso suficiente seguridad?
No. Ocultar botones mejora la experiencia, pero no protege la API. Asume que cualquiera puede llamar a tus endpoints directamente; el servidor debe aplicar permisos y propiedad de tenant en cada lectura y escritura.
¿Qué es la “trampa del admin” y cómo la evito?
“Admin” necesita alcance. Un admin de tenant solo debería gestionar cosas dentro de su tenant, mientras que un admin global puede ver todo y debería ser raro y estar muy controlado. Si tu código trata cualquier admin como global, puedes otorgar acceso entre tenants por accidente.
¿Por qué es arriesgado cargar primero un registro y luego comprobar acceso?
Porque es fácil olvidar un handler, y todavía puedes filtrar información por efectos secundarios (diferencias en errores, tiempos o datos relacionados cargados). El patrón más seguro es incluir reglas de tenant y propiedad directamente en la consulta a la base de datos, de modo que los registros no autorizados nunca se recuperen.
¿Debe el servidor confiar en tenantId o role enviados desde el cliente?
Deriva la identidad y el tenant desde la sesión del servidor o los claims del token, y aplícalos a cada consulta y mutación. Trata cualquier tenantId, role o userId enviado por el cliente como una pista a lo sumo, no algo de confianza.
¿Cuál es la forma más rápida de hacer una prueba de humo para fugas de autorización?
Crea dos cuentas en dos tenants diferentes con datos claramente distintos. Inicia sesión como Tenant B y prueba leer, actualizar y eliminar registros de Tenant A reusando IDs; si algo funciona o devuelve datos reales, tienes una brecha de scoping que hay que arreglar antes del lanzamiento.
¿Por qué las apps CRUD generadas por IA tienen tantos bugs de autorización y qué puedo hacer?
Los prototipos generados por IA suelen resolver la autenticación rápido pero aplican autorización de forma inconsistente en rutas y consultas, especialmente en handlers copiados y endpoints temporales. Si heredaste una codebase así y quieres que sea segura para producción rápido, FixMyMess puede auditar y reparar los handlers que usan solo id, las consultas sin scope y los errores de rol/tenant, a menudo en 48–72 horas tras una auditoría de código gratuita.