Un informe completo de pentest web y API sobre una empresa inventada, Tienda Demo S. A. Es el mismo formato que recibe un cliente: resumen para la gerencia, detalle técnico por hallazgo y anexo de retest.
“Tienda Demo S. A.”, sus sistemas, personas, dominios, credenciales y hallazgos son inventados. Los dominios usan el sufijo reservado .example. No describe a ningún cliente real.
| Cliente | Tienda Demo S. A. (ficticio) |
|---|---|
| Sistema evaluado | Tienda en línea en Next.js y API de comercio en NestJS |
| Tipo de servicio | Pentest web y API, caja gris |
| Referencia | EYM-PT-2026-000 |
| Ventana de pruebas | 5 al 16 de octubre de 2026 |
| Retest | 6 de noviembre de 2026 |
| Clasificación | Confidencial. Uso exclusivo del cliente |
Un atacante sin relación con la empresa, con solo crear una cuenta gratuita, podía convertirse en administrador de la tienda.
Con ese acceso podía ver y modificar los pedidos y los datos personales de todos los clientes, cambiar precios y desactivar productos. Además, cualquier cliente registrado podía ver los pedidos de otros clientes, incluidos nombre, dirección y teléfono.
La buena noticia: las dos fallas más graves tienen correcciones acotadas, de horas a pocos días de trabajo. En el retest, 5 de los 7 hallazgos estaban corregidos, incluidos los dos más graves.
1.2 · Hallazgos por severidad
| Critical | 1 |
| High | 2 |
| Medium | 3 |
| Low | 1 |
| Info | 0 |
| Total | 7 |
|---|
Tienda web, API REST de 46 endpoints documentados y panel administrativo, en staging. Dos cuentas de cliente y una de operador. Fuera de alcance: pasarela de pagos, correo, infraestructura del proveedor de nube, denegación de servicio e ingeniería social.
Metodología: OWASP WSTG v4.2, ASVS 5.0 nivel 2, API Security Top 10 (2023) y CVSS 4.0.
| ID | Hallazgo | Severidad | CVSS 4.0 | Esfuerzo |
|---|---|---|---|---|
| EYM-01 | Tokens JWT firmados con secreto débil y sin expiración | Critical | 9.3 | Bajo |
| EYM-02 | Acceso a pedidos de otros clientes (IDOR / BOLA) | High | 8.6 | Bajo |
| EYM-03 | CORS refleja cualquier origen y permite credenciales | High | 7.1 | Bajo |
| EYM-04 | Clave administrativa del buscador expuesta en el JavaScript público | Medium | 6.9 | Bajo |
| EYM-05 | Sin límite de intentos en el inicio de sesión | Medium | 6.9 | Bajo |
| EYM-06 | Enumeración de usuarios en inicio de sesión y recuperación | Medium | 6.9 | Bajo |
| EYM-07 | Cabeceras de seguridad HTTP ausentes | Low | 2.1 | Bajo |
Descripción
La API emite tokens JWT firmados con HS256 usando un secreto corto y presente en diccionarios públicos de contraseñas. Con un token propio, obtenido al registrar una cuenta gratuita, el secreto se recuperó por fuerza bruta fuera de línea. Conociendo el secreto, es posible firmar tokens con cualquier rol, incluido admin, que la API acepta. Además, los tokens no incluyen exp: un token filtrado sigue siendo válido indefinidamente.
Impacto de negocio
Cualquier persona en internet puede obtener control administrativo total de la tienda. Es una brecha de datos personales con obligación de notificación según la LOPDP y un riesgo directo de fraude.
Evidencia (simulada) · token decodificado, sin campo exp
{ "alg": "HS256", "typ": "JWT" }
{ "sub": "usr_8f2c1a", "email": "cliente.a@tienda.example", "role": "customer", "iat": 1791100800 }Recomendación
Migrar a firma asimétrica (ES256) con la clave privada en un gestor de secretos, expiración de 15 minutos con renovación revocable, aceptar solo el algoritmo esperado e invalidar todos los tokens anteriores.
// auth.module.ts (NestJS)
JwtModule.registerAsync({
inject: [ConfigService],
useFactory: (cfg: ConfigService) => ({
privateKey: cfg.getOrThrow('JWT_PRIVATE_KEY'), // desde el gestor de secretos
publicKey: cfg.getOrThrow('JWT_PUBLIC_KEY'),
signOptions: { algorithm: 'ES256', expiresIn: '15m' },
verifyOptions: { algorithms: ['ES256'] },
}),
});| Prioridad | ID | Acción | Responsable | Esfuerzo | Plazo |
|---|---|---|---|---|---|
| 1 | EYM-01 | Nuevo secreto o firma ES256, expiración de 15 min, renovación revocable | Backend | 1 – 2 días | 72 horas |
| 2 | EYM-02 | Filtro por propietario en pedidos, direcciones y facturas; pruebas de autorización | Backend | 1 día | 7 días |
| 3 | EYM-03 | Lista explícita de orígenes CORS; revisar SameSite | Backend | 2 horas | 7 días |
| 4 | EYM-04 | Rotar clave; clave de solo búsqueda en el navegador | Frontend | 4 horas | 7 días |
Extracto: el informe completo incluye los siete hallazgos y una acción transversal (escaneo de secretos y dependencias en CI, pruebas de autorización por rol).
El retest verifica cada hallazgo después de la corrección. Cinco corregidos, uno parcialmente (falta el límite por cuenta además del límite por IP) y uno con riesgo aceptado temporalmente por el cliente.
| ID | Hallazgo | Severidad | CVSS 4.0 | Retest |
|---|---|---|---|---|
| EYM-01 | Tokens JWT firmados con secreto débil y sin expiración | Critical | 9.3 | Corregido |
| EYM-02 | Acceso a pedidos de otros clientes (IDOR / BOLA) | High | 8.6 | Corregido |
| EYM-03 | CORS refleja cualquier origen y permite credenciales | High | 7.1 | Corregido |
| EYM-04 | Clave administrativa del buscador expuesta en el JavaScript público | Medium | 6.9 | Corregido |
| EYM-05 | Sin límite de intentos en el inicio de sesión | Medium | 6.9 | Parcial |
| EYM-06 | Enumeración de usuarios en inicio de sesión y recuperación | Medium | 6.9 | Corregido |
| EYM-07 | Cabeceras de seguridad HTTP ausentes | Low | 2.1 | Riesgo aceptado |
Siguiente paso
Entendemos su sistema, lo que le preocupa y el plazo, y le decimos si podemos ayudar. La llamada no tiene costo y no compromete a nada.