BOLA: el agujero más explotado de las APIs modernas
· 11 min de lectura
Broken Object Level Authorization (BOLA) encabeza la lista OWASP API Top 10. Aprende por qué es tan común, cómo se detecta cambiando un ID en la URL, cómo se abusa a escala y cómo se protege correctamente.
Las APIs REST y GraphQL dominan la web moderna: cada aplicación móvil, cada SPA, cada microservicio se comunica por APIs. Y con ellas creció una nueva categoría de fallos que OWASP recoge en su API Security Top 10. En la primera y última edición, el número uno es siempre el mismo: BOLA — Broken Object Level Authorization.
BOLA es el fallo que ocurre cuando una API expone un recurso identificado por un ID (un usuario, un pedido, una factura) y no verifica que el solicitante tenga permiso para leer o modificar ese recurso específico. La autenticación funciona (sabe quién eres), pero la autorización por objeto no (no verifica que ese objeto sea tuyo). Resultado: cambias un número en la URL y accedes a los datos de otro usuario.
Suena a chiste, pero sigue siendo el fallo más reportado en bug bounty en 2026. En esta lección vas a ver qué es BOLA, cómo detectarlo manual y con herramientas, variantes comunes, abusos a escala, y cómo defenderse. Probado en el laboratorio profilepeek de whoami-labs.
Prueba solo contra APIs autorizadas o los laboratorios. Acceder a datos de otros usuarios en producción sin permiso es delito.
Qué es BOLA#

Imagina una API de e-commerce que expone:
GET /api/orders/12345 HTTP/1.1
Authorization: Bearer eyJ...tokenDeMaria
La API verifica que el token es válido (autenticación OK), consulta el pedido 12345 y lo devuelve. Lo que no verifica: que el pedido 12345 pertenezca a María. Si Juan cambia el 12345 por 12346, la API le devuelve el pedido de otro cliente. Direcciones, importes, teléfonos, histórico. Exactamente lo que no debería ocurrir.
Dónde encontrarlo#
Casi cualquier endpoint que acepte un identificador en la URL o en el cuerpo es candidato:
- Recursos directos:
/api/users/<id>,/api/orders/<id>,/api/invoices/<id>. - Relaciones anidadas:
/api/users/<id>/profile,/api/projects/<id>/tasks. - Operaciones de escritura:
POST /api/orders/<id>/cancel,PATCH /api/users/<id>. - Downloads:
/api/documents/<id>/download,/api/images/<id>. - GraphQL: queries donde
userIdes un argumento.
Donde hay un ID (numérico, UUID, slug) hay candidato a BOLA.
Detección manual#
Paso 1: entender la autenticación#
Lo primero: obtener dos cuentas válidas (A y B). Si la aplicación permite registro, crea dos usuarios normales.
Paso 2: mapear los endpoints#
Usa la aplicación con A y captura todas las peticiones con Burp o la DevTools. Identifica los endpoints que usan IDs del propio usuario.
Paso 3: cambiar IDs#
Con A autenticado, intenta acceder a un recurso cuyo ID conoces de B:
GET /api/orders/42 HTTP/1.1
Authorization: Bearer <token-de-A>
Si la respuesta es 200 y devuelve los datos de B, tienes BOLA. Si es 401/403, el control funciona.
Paso 4: probar variantes#
- IDs predecibles: si los IDs son secuenciales, enumera. Scripts simples con
curlbarren centenares en minutos. - UUIDs: aparentemente aleatorios, pero a veces aparecen en logs, URLs públicas, hashes de redes sociales. Si los conoces, pruébalos.
- Cambiar el objeto a uno que no existe: una 404 muy distinta de una 403 revela que el control de autorización se aplica después de encontrar el objeto (típico fingerprint de BOLA).
Detección semi-automatizada#
Burp: Autorize y Auto Repeater#
Instala la extensión Autorize en Burp. Le pasas dos juegos de cookies/tokens (A y B) y, mientras navegas con A, Burp lanza automáticamente cada petición también como B y marca qué endpoints devuelven información accesible con A pero que deberían ser solo de B.
Con scripts#
import httpx
TOKEN = "eyJ..."
h = {"Authorization": f"Bearer {TOKEN}"}
for i in range(1, 1000):
r = httpx.get(f"https://api.objetivo.com/orders/{i}", headers=h)
if r.status_code == 200:
print(f"BOLA? orden {i}: {r.json().get('total')}")
Un bucle sencillo barre IDs numéricos consecutivos. Si varias respuestas 200 llegan con datos de distintos clientes, estás ante un BOLA masivo.
Postman / Hoppscotch#
Para APIs sin aplicación cliente estándar (APIs internas, de back-office), importar la colección en Postman y ejecutar «runner» con variables te permite probar decenas de combinaciones de forma estructurada.
Variantes comunes#

BOLA en el body#
POST /api/orders/cancel HTTP/1.1
Content-Type: application/json
Authorization: Bearer <token-de-A>
{"order_id": 42}
Si el endpoint cancela cualquier pedido por ID sin verificar propietario, BOLA.
BOLA en query strings#
GET /api/documents?doc_id=42 HTTP/1.1
Authorization: Bearer <token-de-A>
Mismo patrón, parámetro distinto.
BOLA en JWT con sub mal manejado#
Un JWT lleva sub con el user ID. Si el servidor lee el userId del body de la petición en vez del sub del token, un atacante puede manipular el body y suplantar:
PATCH /api/users/42 HTTP/1.1
Authorization: Bearer <token-de-A>
Content-Type: application/json
{"user_id": 42, "email": "[email protected]"}
Broken Function Level Authorization (BFLA)#
Variante relacionada: la API expone endpoints de admin a usuarios normales porque no verifica el rol. /api/admin/users llamado por un usuario normal devuelve 200 con el listado completo. OWASP lo trata como un ítem separado (API5).
Abuso a escala#
Cuando el BOLA permite enumerar un recurso secuencial, el impacto crece exponencialmente:
- Exfiltración de base de clientes: 100.000 IDs en secuencia, los recorres en horas.
- Exfiltración de PII: datos personales de miles de usuarios.
- Manipulación masiva: endpoints de escritura permiten cambiar perfiles, cancelar pedidos, enviar mensajes en nombre de otros.
- Takeover de cuentas: cambiar email o contraseña de otro usuario si el endpoint no verifica propietario.
Es por eso que BOLA tiene impacto desproporcionado respecto a muchos otros fallos: un solo endpoint vulnerable puede exponer la base entera de clientes.
Defender contra BOLA#
La regla es simple y universal: toda operación sobre un recurso tiene que verificar que el usuario autenticado tiene permiso sobre ese recurso específico. No es opcional, no es «lo haremos si da tiempo»: es el control más básico de autorización.
Patrones concretos:
# Mal (vulnerable):
def get_order(order_id):
return db.query(Order).filter_by(id=order_id).first()
# Bien:
def get_order(order_id, current_user):
return db.query(Order).filter_by(id=order_id, user_id=current_user.id).first()
El filtro user_id=current_user.id no es cortesía: es el control de autorización. Sin él, BOLA.
Mejor aún, encapsularlo en el ORM o en una capa de middleware para que no dependa de la memoria del desarrollador:
- Policies/Guards: Laravel Policies, Django Guardian, NestJS Guards expresan la regla en un sitio y la aplican en cada ruta.
- IDs no predecibles: UUIDs v4 en vez de enteros reducen el blast radius si falla la autorización (no evitan BOLA, pero dificultan enumerar).
- Rate limiting por usuario: dificulta la enumeración masiva.
- Logs de accesos: registrar quién accede a qué objeto permite detectar abuso.
- Pruebas unitarias de autorización: tests que verifiquen que
A no puede leer recurso de B.
Cómo auditar una API para BOLA de forma sistemática#
- Enumera endpoints (Swagger, OpenAPI, Postman collection, GraphQL introspection).
- Clasifica los que tocan un recurso con ID.
- Para cada uno, prueba con dos usuarios diferentes manipulando el ID.
- Documenta resultado: 200 con datos ajenos = vulnerable; 403 = correcto.
- Prueba también operaciones de escritura (
POST,PATCH,DELETE): BOLA de escritura es más grave que de lectura.
Casos reales famosos#
BOLA ha sido responsable de brechas sonadas. Algunas que vale la pena conocer:
- Facebook (2015): un investigador pudo borrar fotos ajenas cambiando el ID del post en una petición de la API de álbumes. Pagado por el programa de bug bounty.
- Uber (2016): la API móvil permitía consultar datos de cualquier conductor cambiando el UUID. Reportado y parcheado.
- Peloton (2021): endpoints de la API devolvían datos de cualquier usuario (edad, género, ubicación, estadísticas) sin verificar propietario. 3 millones de usuarios afectados.
- T-Mobile (2023): una API expuso datos de 37 millones de clientes por BOLA. Uno de los incidentes más grandes del año.
- Peloton nuevamente (2022): segunda instancia con otra variante del mismo problema en endpoints diferentes.
El patrón se repite: APIs públicas, autenticación correcta, autorización por objeto ausente, enumeración secuencial masiva. En cada caso el fix es la misma línea de código: filtrar por user_id en la consulta. En cada caso el coste de no haberla puesto fue millonario.
Comparado con otros fallos API#
| Fallo | Qué es | Diferencia con BOLA |
|---|---|---|
| BOLA (API1) | Autorización por objeto rota | Es el que estudiamos aquí |
| Broken Auth (API2) | Autenticación mal implementada | El token es inválido o se puede forjar |
| BOPLA (API3) | Property-level, lees/escribes campos ajenos | Mismo objeto, pero campos que no deberías tocar |
| BFLA (API5) | Function-level, llamas a endpoints de otro rol | /api/admin/* desde un user normal |
| Mass Assignment | Enviar campos extra que modifican campos sensibles | {"is_admin": true} en un PATCH |
| SSRF (API7) | El servidor hace requests que controla el atacante | Otro vector, no relacionado |
En auditorías de APIs se evalúan todos; BOLA es el más repetido pero no el único.
Errores comunes#
- Confiar en que el frontend oculta IDs ajenos como protección. El frontend no protege nada.
- Validar solo que el token es válido, no que el objeto pertenece al usuario.
- Usar UUIDs como «autorización por obscuridad» sin control real.
- No probar los endpoints de escritura: a veces el GET está bien y el PATCH está roto.
- Olvidar GraphQL: queries como
query { user(id: 42) { email, phone } }son candidatos perfectos.
Preguntas frecuentes#
¿Por qué BOLA es tan común?#
Porque es fácil olvidarlo. La autenticación la pone el framework; la autorización por objeto depende de que cada desarrollador la implemente correctamente en cada endpoint. Un solo olvido → BOLA.
¿Qué diferencia hay entre IDOR y BOLA?#
IDOR (Insecure Direct Object Reference) es el nombre histórico del mismo patrón en aplicaciones web clásicas. BOLA es la versión moderna para APIs REST/GraphQL. Son el mismo concepto.
¿Los frameworks modernos lo previenen?#
Algunos tienen helpers (Laravel Policies, Django Guardian, Spring Security), pero ninguno lo evita por defecto. Depende siempre del desarrollador aplicarlos en cada endpoint.
¿GraphQL es más o menos vulnerable?#
En el papel igual: donde haya un ID como argumento, cabe BOLA. En la práctica, GraphQL introspection expone esquemas que facilitan descubrirlos. Buenas herramientas: InQL, GraphQL Voyager.
¿Dónde practico?#
En el laboratorio profilepeek de whoami-labs, una API con endpoints típicos vulnerables a BOLA en GET y PATCH. Practicas detección manual con Burp, scripts de enumeración y la variante escritura con cambio de email.
¿Cómo lo reporto en un informe de pentest?#
Como fallo High o Critical (según sensibilidad del recurso) con:
- Descripción del endpoint, ejemplo de petición vulnerable, respuesta esperada vs real.
- Impacto cuantificado: cuántos objetos pudiste acceder sin permiso, qué tipo de dato se expuso (PII, financiero, salud).
- Reproducción paso a paso con dos cuentas de prueba.
- Recomendación de fix concreta: filtrar por
user_iden la consulta, añadir policies. - Referencias a OWASP API1 y a casos públicos equivalentes para dar contexto al cliente.
¿Puedo detectar BOLA leyendo solo el código?#
Sí, es de los fallos más fáciles de encontrar en revisión. Buscas consultas al ORM con findById(id), filter(id=id), etc., sin filtro adicional de propietario. Es más barato que la auditoría dinámica y suele dar resultados en minutos para equipos que no tienen cultura de autorización explícita.
Resumen#
- BOLA es el fallo nº1 de la API Security Top 10 de OWASP: cambiar un ID en una URL para acceder a recursos ajenos.
- Detección: dos cuentas, probar que A no pueda leer/modificar objetos de B.
- Herramientas: Burp + Autorize, scripts Python con
httpx, Postman runner. - Variantes: ID en path, body, query, JWT mal validado.
- Defensa: filtrar por
user_iden cada consulta, usar policies/guards, rate limiting y tests de autorización.