BOLA em APIs: por que ainda é o achado nº 1 e como encadeamos até dados de outros clientes
Broken Object Level Authorization lidera o OWASP API Top 10 há anos e continua sendo o achado crítico mais comum nos nossos pentests de API. O mecanismo, as variantes que scanners não pegam e o que fazer.

Um número no lugar errado
GET /api/v2/invoices/48213 devolve a fatura do usuário logado. GET /api/v2/invoices/48212 devolve a fatura de outro cliente. Sem erro, sem log, sem alerta. Esse é o BOLA — Broken Object Level Authorization —, item API1 do OWASP API Security Top 10, o mesmo problema que a comunidade web chamava de IDOR.
É o achado crítico mais frequente nos nossos pentests de API, e não por descuido dos times: ele nasce de uma decisão de arquitetura razoável (identificar objetos por ID) combinada com uma verificação que parece existir mas está no lugar errado.
Por que scanners não encontram
Um scanner não sabe o que é "seu" e o que é "do outro". Ele vê duas respostas 200 com JSON válido e segue em frente. Detectar BOLA exige dois contextos autenticados, entendimento do modelo de dados e a pergunta certa: esse usuário deveria ver isso? Isso é trabalho manual — ou tooling próprio que carrega o contexto de identidade, que é como fazemos.
As variantes que mais encontramos
1. ID sequencial ou previsível
O caso clássico. Inteiro incremental, timestamp, CPF, e-mail na URL. Enumerável em minutos.
2. UUID que vaza em outro lugar
"Usamos UUID v4, não dá para adivinhar." Verdade — mas o UUID do cliente aparece na resposta de /api/orders, no link do e-mail de confirmação, no HTML da página pública, no webhook para o parceiro. Obscuridade não é autorização.
3. Autorização só no GET, não no PATCH
O time protegeu a leitura. A escrita (PUT, PATCH, DELETE) usa outro handler, escrito depois, sem o mesmo middleware. Ler é ruim; alterar o endereço de entrega ou a chave PIX de outro cliente é pior.
4. O ID no corpo, não na URL
POST /api/transfer com {"from_account": "...", "to_account": "..."}. O backend confia no from_account enviado pelo cliente em vez de derivá-lo da sessão. Vimos isso em fintech regulada.
5. GraphQL e batch
query { user(id: 48212) { email, documents { url } } }. Resolvers aninhados frequentemente checam autorização só no nó raiz. Com aliases e batching, enumeram-se milhares de objetos numa única requisição.
6. Endpoints "internos" ou legados
/api/v1/ ficou no ar depois da /v2/. Ou /internal/export sem autenticação porque "só o frontend admin chama". O frontend não é fronteira de segurança.
7. Autorização por tenant, não por objeto
Em SaaS multi-tenant, checa-se se o usuário pertence à empresa X — mas não se o objeto pertence à empresa X. Um usuário de X lê objetos de Y trocando o ID.
Como encadeamos: do 200 ao impacto de negócio
Um BOLA sozinho é grave. O que o relatório precisa mostrar é o caminho até o dano real:
- Leitura de fatura de outro cliente → dados pessoais (LGPD/GDPR).
- A fatura traz o UUID do documento → download do PDF com dados bancários.
- O mesmo padrão em
PATCH /api/users/{id}→ troca de e-mail de recuperação → account takeover. - Com a conta, acesso a
POST /api/payouts→ movimentação financeira.
Cada passo é uma requisição documentada com request/response no relatório. O board não precisa entender IDOR; precisa entender "qualquer usuário conseguia mudar a chave PIX de qualquer outro".
O que corrige de verdade
- Derive a identidade da sessão, nunca do input. O
from_accountvem do token, não do JSON. - Autorize no objeto, em toda operação. Um único ponto (policy, middleware, repositório) que responde "este sujeito pode fazer esta ação neste objeto?" — e todos os handlers passam por ele, incluindo GraphQL resolvers e jobs internos.
- Escopo na consulta, não depois.
WHERE id = ? AND owner_id = ?no banco. Filtrar em memória depois de buscar tudo é convite a vazamento. - Teste automatizado de autorização na CI: para cada endpoint, dois usuários, um objeto de cada, asserção de 403/404. Isso evita regressão; não substitui o pentest, que encontra os caminhos que ninguém escreveu teste para.
- Rate limit e alerta em padrões de enumeração — não impede, mas encurta a janela.
- Retire o legado do ar. Versões antigas de API precisam de data de desligamento, não de esquecimento.
O que pedir no seu próximo pentest de API
Exija que o teste seja feito com pelo menos dois usuários por papel e com o OpenAPI/Swagger em mãos (grey-box). Peça cobertura explícita de BOLA, BFLA (autorização em nível de função, API5), mass assignment (API3) e dos endpoints não documentados que o recon encontrar. E peça o encadeamento: um relatório com 30 IDORs isolados vale menos que um com o caminho até o takeover.
Como a Pentest Machine testa isso
Nosso API Pentest é guiado pelo OWASP API Top 10 e pela especificação da sua API, com múltiplas identidades por papel e tooling próprio que carrega contexto de autorização durante a enumeração — o que permite testar milhares de combinações objeto × usuário × operação sem perder a análise manual dos encadeamentos. Cada achado vem com PoC reproduzível, impacto de negócio e o padrão de correção, e o reteste está incluso.