pular para o conteúdo
voltar ao mapa
técnica
etapa: operate
3 min de leitura

A10 Mishandling of Exceptional Conditions

A segurança muitas vezes depende do que acontece quando algo dá errado. Se um erro significa "permitir", um stack trace significa "aqui está o meu código" ou uma operação pela metade significa "estado corrompido", o caminho de falha é a vulnerabilidade.

Chaos engineering (fault injection)Fuzzers (AFL++, Atheris, go-fuzz)Semgrep (empty catch, swallowed errors)Hypothesis / property-based testingToxiproxy

O que é

O tratamento inadequado de condições excepcionais é a preparação, detecção e resposta indevidas a situações incomuns: dependências que falham, timeouts, entrada malformada, esgotamento de recursos, escritas parciais e estados inesperados. Os erros típicos são falhar aberto, vazar detalhes em mensagens de erro, engolir exceções e deixar transações pela metade.

É uma categoria nova no :2025 (A10) e reúne várias fraquezas mais antigas em torno do tratamento de erros.

Como o ataque funciona

  • Fail open: um serviço de autorização sofre timeout e o código trata a exceção como "sem restrição".
  • Vazamento de informação: um erro de banco de dados é devolvido ao cliente com o nome da tabela, a consulta e a versão do driver.
  • Erros engolidos: um catch vazio esconde uma falha na verificação de assinatura e o processamento continua.
  • Estado parcial: um pagamento é cobrado, mas a escrita do pedido falha; tentar de novo duplica a cobrança.
  • Esgotamento de recursos: uma entrada sem limite ou uma exceção não tratada em um loop permite que uma única requisição derrube o serviço.

Código vulnerável

A verificação falha aberta, o erro vaza detalhes internos e a atualização em várias etapas não é atômica.

access.pypython
def can_access(user, doc):
    try:
        return policy_service.allowed(user.id, doc.id)
    except Exception:
        return True                    # o serviço caiu, então deixe entrar

@app.errorhandler(Exception)
def on_error(e):
    return str(e), 500                 # vaza detalhes internos ao cliente
transfer.jsjavascript
await accounts.debit(from, amount);
await accounts.credit(to, amount);   // se isto lançar um erro, o dinheiro sumiu

A correção

Falhe fechado: diante de qualquer dúvida sobre uma decisão de segurança, negue. Devolva ao cliente uma mensagem genérica com um e mantenha os detalhes nos logs. Torne atômicas as mudanças em várias etapas com uma transação e limite tudo: tempo, tamanho, retentativas, memória.

access.pypython
def can_access(user, doc):
    try:
        return policy_service.allowed(user.id, doc.id, timeout=0.5)
    except Exception:
        log.exception("policy check failed", extra={"user": user.id, "doc": doc.id})
        return False                   # falha fechada

@app.errorhandler(Exception)
def on_error(e):
    rid = uuid4().hex
    log.exception("unhandled error", extra={"request_id": rid})
    return {"error": "internal error", "request_id": rid}, 500
transfer.jsjavascript
await db.transaction(async (trx) => {
  await accounts.debit(from, amount, trx);
  await accounts.credit(to, amount, trx);   // ou acontecem os dois ou nenhum
});
client.gogo
ctx, cancel := context.WithTimeout(r.Context(), 800*time.Millisecond)
defer cancel()

resp, err := policy.Check(ctx, user, doc)
if err != nil {
	log.Error("policy check failed", "err", err)
	http.Error(w, "forbidden", http.StatusForbidden) // falha fechada
	return
}

Prove a correção

Injete a falha de propósito. Faça a dependência sofrer timeout e verifique que o acesso é negado; faça a segunda etapa lançar um erro e verifique que nada mudou; provoque um erro e verifique que a resposta não traz detalhes internos. O fuzzing acrescenta entradas estranhas em que você não pensou.

test_failures.py (pytest)python
def test_denies_when_policy_service_is_down(monkeypatch, user, doc):
    monkeypatch.setattr(policy_service, "allowed", lambda *a, **k: (_ for _ in ()).throw(TimeoutError()))
    assert can_access(user, doc) is False

def test_error_response_has_no_internals(client, monkeypatch):
    monkeypatch.setattr(db, "query", lambda *a, **k: (_ for _ in ()).throw(RuntimeError("relation users_secret does not exist")))
    body = client.get("/api/things").get_json()
    assert "users_secret" not in str(body) and "request_id" in body

@given(st.text())
def test_parser_never_crashes_on_any_text(s):      # Hypothesis
    parse_input(s)       # pode rejeitar (ValueError), mas não pode lançar nenhuma outra exceção
transfer.test.jsjavascript
test("a failed credit rolls back the debit", async () => {
  jest.spyOn(accounts, "credit").mockRejectedValue(new Error("boom"));
  const before = await accounts.balance(from);
  await expect(transfer(from, to, 50)).rejects.toThrow();
  expect(await accounts.balance(from)).toBe(before);
});

Checklist

  • Decida de antemão o comportamento de falha de cada verificação de segurança: deve negar.
  • Capture com precisão; nunca deixe um catch vazio; registre com contexto e relance a exceção ou devolva um erro seguro.
  • Devolva erros genéricos com um correlation id; mantenha stack traces e consultas apenas nos logs.
  • Use transações e chaves de idempotência em operações de várias etapas, para que as retentativas sejam seguras.
  • Defina timeouts, limites de tamanho, rate limits e orçamentos de retentativa em toda chamada externa e entrada.
  • Pratique a falha: injeção de falhas, fuzzing e game days revelam caminhos fail-open antes dos atacantes.
OWASP Top 10A lista de referência mais famosa de riscos de segurança em aplicações web (A01 acesso quebrado, A02 falhas criptográficas, A03 injeção...), revisada a cada alguns anos pela comunidade OWASP. É um mapa educacional de categorias de risco — não um checklist de ferramenta nem uma certificação.ver no glossário →Correlation idrequest idUm id único anexado a uma requisição e a cada linha de log que ela gera, exibido ao usuário nas mensagens de erro para que o suporte encontre os detalhes sem vazá-los.ver no glossário →

conexões no mapa

atualizado em 14/10/2026 · fontes para aprofundar · reportar erro

em outros domínios

Estude antes

teste o que entendeu

Carregando perguntas…