Eliminación y modificación cruzada de usuarios de filas del carrito y de la lista de deseos en la plantilla de comercio electrónico a través de consultas de clave primaria sin alcance
Descripción
Elusión de autorización mediante clave controlada por el usuario (CWE-639) en los repositorios de carrito y lista de deseos de MarcosCamara01 Ecommerce Template, en cartRepository.delete(), cartRepository.updateQuantityInternal() y wishlistRepository.delete() (src/lib/db/drizzle/repositories/). Cualquier usuario autenticado puede eliminar y modificar las filas de carrito y lista de deseos de cualquier otro usuario.
Las tres consultas localizan las filas únicamente por clave primaria, sin ningún predicado sobre el usuario propietario. La autorización por usuario de esas operaciones recae en el row level security de PostgreSQL: el contexto de usuario se fija por transacción con set_config('app.current_user_id', userId, true) en connection.ts, y las políticas comparan app.current_user_id() con user_id.
Ese control no opera. Las migraciones ejecutan ALTER TABLE ... ENABLE ROW LEVEL SECURITY pero nunca ALTER TABLE ... FORCE ROW LEVEL SECURITY, y PostgreSQL no aplica las políticas al rol propietario de la tabla. El template emplea un único DATABASE_URL tanto para ejecutar las migraciones, que crean las tablas y convierten así a ese rol en propietario, como para la aplicación en ejecución, de modo que la aplicación conecta como propietaria y las políticas no se le aplican.
cart_items.id y wishlist.id son valores bigserial secuenciales, por lo que los identificadores de las filas de otros usuarios pueden enumerarse en lugar de adivinarse, y el ataque puede recorrerse sobre todas las cuentas de la instalación. La ruta de actualización devuelve la fila modificada, que contiene el identificador del usuario al que pertenece.
Sólo esas tres operaciones son alcanzables. El resto de las consultas de los repositorios incluyen su propio predicado explícito de user_id y no están afectadas, por lo que este registro cubre las tres operaciones demostradas y no el conjunto del modelo de autorización.
Tipo de vulnerabilidad (CWE)
- CWE-639: Elusión de autorización mediante clave controlada por el usuario
Versiones afectadas
Afectado desde el commit b139a11c del 24 de diciembre de 2025, donde se introdujeron estos repositorios con predicados únicamente de clave primaria, y corregido en el commit adf7dedb del 27 de julio de 2026. Estado por defecto: no afectado.
En el límite inferior las migraciones no contenían ninguna política de row level security, de modo que las tres operaciones no tenían autorización por usuario de ningún tipo. Las políticas llegan después, en el commit 63f94f5 del 1 de abril de 2026, y son inoperantes por el motivo anterior, por lo que la exposición es continua en todo el rango.
El proyecto no publica versiones y el repositorio no tiene etiquetas de git, y el campo version de package.json se ha mantenido en 0.1.0, por lo que una revisión afectada sólo puede identificarse por commit.
Puntuación (CVSS 4.0)
Alta (7.1)
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:H/VA:N/SC:N/SI:N/SA:N
Los privilegios requeridos son Bajos porque el atacante necesita una cuenta corriente en la tienda y nada más. La interacción del usuario es Ninguna porque el atacante actúa por sí solo contra la API. La confidencialidad del sistema vulnerable es Baja porque la respuesta de actualización devuelve la fila de la víctima, lo que revela su identificador de usuario y la variante y la talla que había seleccionado, y nada más allá de eso. La integridad del sistema vulnerable es Alta porque la eliminación y la modificación alcanzan filas que pertenecen a otra cuenta y las destruyen o alteran, y una escritura se puntúa Baja sólo cuando queda confinada a algo sin consecuencia directa, que el contenido del carrito y de la lista de deseos de un usuario no es. La disponibilidad es Ninguna porque la tienda sigue operando y no se impide a la víctima su uso. Las métricas del sistema subsiguiente son Ninguna, ya que la comprobación ausente es autorización interna de la aplicación.
Solución
Actualizar a una revisión que incluya el commit adf7dedb del 27 de julio de 2026.
Un operador que no pueda actualizar puede obtener el mismo efecto ejecutando la aplicación con un rol de base de datos que no sea propietario de las tablas, o aplicando ALTER TABLE ... FORCE ROW LEVEL SECURITY a las tablas que tienen políticas, lo que hace que las políticas existentes se apliquen también al propietario.
Parche
Commit adf7dedb. Corrige el problema en las dos capas. Las tres consultas dejan de depender del row level security: cartRepository.delete() y wishlistRepository.delete() filtran ahora por el userId que ya recibían, y updateQuantityInternal() recibe un userId y filtra por él, propagado desde upsert() y updateQuantity(). Una nueva migración 0004_force_rls.sql aplica después FORCE ROW LEVEL SECURITY a todas las tablas que tienen políticas, de modo que las políticas se apliquen también al rol propietario, y cada capa bloquea el ataque por sí sola.
Créditos
- Darío Rivas - descubridor
- Gerard Martinez Guillamon - descubridor
- Cristian Fernández Cornejo - analista
- Xoán M. Otero Jorge - analista
- Secur0 CNA - coordinador
- MarcosCamara01 - desarrollador de la corrección
Origen del descubrimiento: Interno
Registro oficial: CVE-2026-115453
Registros relacionados
- CVE-2026-115450 - manipulación de precio en el flujo de pago de la misma aplicación