BOLA en fintech: 1 endpoint, R$ 200k en riesgo (caso real)
En un pentest a una fintech brasileña, un BOLA en un endpoint de tarjetas dejaba al cliente A ver el historial del cliente B. Análisis técnico anonimizado.
Investigador de seguridad y fundador de No Vuln

En un pentest a una fintech brasileña que realizamos hace poco, encontramos un BOLA (Broken Object Level Authorization) en un endpoint de tarjetas. El cliente A podía ver TODO el historial de transacciones del cliente B cambiando un solo parámetro en la URL.
Estimación de exposición si lo explotara un atacante real: filtración del historial transaccional de toda la base activa — millones de transacciones, con el mapeo completo entre tarjeta, monto y comercio. En términos de la LGPD (la ley brasileña de protección de datos): dato personal financiero de cientos de miles de titulares. Multa potencial: hasta el 2% de la facturación (tope de R$ 50M por infracción).
Este post es el análisis técnico anonimizado de lo que pasó — porque el patrón se repite en casi toda fintech brasileña que auditamos. Si operas un SaaS B2B, una fintech, un marketplace o cualquier plataforma multi-tenant, es lectura obligatoria.
El descubrimiento
El cliente nos contrató para un pentest de caja gris (grey box) completo de la plataforma. Recibimos credenciales de 2 cuentas de prueba — vamos a llamarlas Cuenta A y Cuenta B. Ambas eran cuentas corporativas legítimas, con tarjetas corporativas asignadas.
En el mapeo inicial, identificamos el endpoint que servía el historial de transacciones de una tarjeta:
GET /api/v2/cards/{card_id}/transactionsAuthorization: Bearer <token_de_la_cuenta>
Comportamiento esperado: cada cuenta ve solo las transacciones de sus propias tarjetas.
Comportamiento real: reemplazando {card_id} por un UUID de tarjeta de la Cuenta B, el servidor devolvía el historial completo — para la Cuenta A autenticada con su propio token.
El bug en detalle
La implementación validaba solamente:
- ✅ Que el token Bearer fuera válido (cualquier usuario autenticado pasaba)
- ✅ Que el
card_idexistiera en la base de datos - ❌ Que el
card_idperteneciera al tenant del usuario autenticado
La 3ª validación — la esencial — simplemente no existía. El endpoint confiaba en que, si conocías el UUID de la tarjeta, tenías derecho a ver el historial.
Esto es BOLA (Broken Object Level Authorization) — la vulnerabilidad #1 del OWASP API Security Top 10. No es un bug oscuro. Es uno de los vectores más explotados en ataques reales a APIs en 2026. Mira el análisis técnico detallado de las 3 fallas que dominan las APIs en nuestra guía de BOLA, BOPLA y BFLA.
Por qué este bug aparece tanto
Tres patrones arquitectónicos predisponen al bug:
Patrón 1: un ORM que esconde la query
Cuando el ORM facilita escribir una query sin el filtro de tenant, en code review parece correcta, pero en runtime abre un BOLA. Por ejemplo, en Python/Django:
- ❌
Card.objects.get(id=card_id)— sin filtro de tenant - ✅
Card.objects.get(id=card_id, tenant_id=user.tenant_id)— con filtro
La línea equivocada parece “correcta” en code review. Quien la escribe está enfocado en el ID del recurso, no en el contexto de autorización. En runtime, BOLA abierto.
Patrón 2: autorización “vía middleware” insuficiente
Muchas aplicaciones implementan un middleware de autenticación (valida el token) y creen que eso es autorización. No lo es.
- Autenticación responde: ¿quién eres?
- Autorización responde: ¿qué puedes hacer?
Sin un middleware que valide el ownership del recurso, la autorización queda como responsabilidad del dev en cada endpoint — y en algún momento alguien se olvida.
Patrón 3: los UUID dan una falsa sensación de seguridad
Los devs suelen racionalizar: “El UUID tiene 128 bits. El atacante no lo va a adivinar”.
Es verdad — el atacante no lo adivina. Pero el atacante:
- Obtiene UUID en respuestas legítimas (listados, webhooks emitidos, logs)
- Encuentra UUID filtrados en URLs compartidas
- Recolecta UUID en integraciones con terceros
- Consigue UUID vía otros bugs (info disclosure, IDOR en otros endpoints)
Obscurity ≠ security. El UUID no reemplaza a la autorización.
Cómo lo encuentra un investigador
En un pentest serio, BOLA es el primer lugar donde miramos. El proceso:
- Crear 2 cuentas en tenants distintos (esencial — no se puede hacer con 1 cuenta)
- Mapear exhaustivamente todos los endpoints que reciben un ID/UUID en la URL o en el body
- Para cada endpoint, cambiar el ID por uno que pertenezca al otro tenant
- Observar la respuesta — 200 OK con datos = BOLA confirmado
- Documentar con una PoC reproducible — request exacto, response exacto, severidad calibrada
Un scanner automatizado NO hace esto. No tiene múltiples sesiones, no crea cuentas, no correlaciona datos entre tenants. Solo lo detecta un investigador humano.
En los SaaS B2B brasileños que auditamos en 2026, un BOLA en al menos 1 endpoint aparece en cerca del 85% de los proyectos.
Cómo corregirlo — defense in depth en 4 capas
Capa 1: middleware de tenant scoping
Un decorator o middleware que valida el ownership de forma automática:
@tenant_scoped(resource='card', param='card_id')antes de la view- Validación automática antes de que se ejecute cualquier lógica de la view
- Centraliza la autorización en 1 lugar — no depende de que el dev se acuerde
Capa 2: query con filtro obligatorio
Toda query SQL relacionada con un recurso de tenant debe incluir tenant_id en WHERE:
SELECT * FROM transactions WHERE card_id = $1 AND tenant_id = $2- Un lint de SQL o un helper del ORM que rechace la query sin
tenant_id
Capa 3: Row-Level Security (PostgreSQL)
Defense in depth en la base de datos: PostgreSQL bloquea de forma nativa vía CREATE POLICY tenant_isolation. Si la Capa 1 falla y la Capa 2 falla, la Capa 3 todavía protege.
Capa 4: pruebas automatizadas de autorización en el CI
Una suite de pruebas que crea 2 cuentas en tenants distintos e intenta el acceso cruzado en cada endpoint sensible. El pipeline falla si se introduce un BOLA en un PR. Ese es el control preventivo definitivo.
El costo de no corregirlo
En el caso real, calculamos:
- Volumen de datos expuestos si se explota: ~12 millones de transacciones (toda la base activa)
- Categoría LGPD: dato personal financiero (alta sensibilidad)
- Multa LGPD máxima: R$ 50M (tope por infracción)
- Costo de comunicación: notificación obligatoria a la ANPD (la autoridad brasileña de protección de datos) y a todos los titulares afectados
- Costo de litigio: acciones colectivas (Procon, el organismo brasileño de defensa del consumidor, y acciones civiles públicas)
- Churn estimado: 4 de cada 10 clientes brasileños no vuelven tras un incidente (Akamai, 2024)
El bug se corrigió en las 72h siguientes a nuestro informe. Nunca fue explotado por un atacante real, hasta donde se sabe.
Qué hacer hoy
Si tu plataforma es multi-tenant (SaaS B2B, fintech, marketplace, e-commerce con vendedores, healthtech con clínicas):
- Auditoría de los endpoints que reciben un ID/UUID — lístalos todos a mano
- Para cada uno, valida: ¿existe un filtro de tenant_id en el servidor?
- Si no estás seguro: contrata un pentest enfocado en BOLA cross-tenant
- Implementa las 4 capas de arriba como patrón arquitectónico
Si eres founder/CTO y estás pensando “esto no nos puede pasar a nosotros, nuestro equipo es bueno” — es exactamente lo que dicen todos los equipos que descubren un BOLA en producción 6 meses después.
La diferencia entre un equipo bueno y un equipo vulnerable no es el talento — es el proceso de validación adversarial.
Para hablar de un pentest enfocado en el aislamiento multi-tenant, mira las páginas dedicadas: pentest para fintech, pentest para SaaS y pentest para marketplace. Para entender más sobre las clases de falla que dominan las APIs en 2026, mira BOLA, BOPLA y BFLA.
Siguiente paso
¿Quieres aplicar esto a tu sistema?
No Vuln hace pentests en profundidad con la misma metodología descrita en este artículo. Solicita una propuesta: NDA bilateral en 24h y alcance definido en una llamada técnica.