
Mergulho profundo em uma injeção SQL crítica no Ormar ORM do Python — reprodução, correção e testes
Uma análise aprofundada de uma vulnerabilidade crítica (CVSS 9.8) de injeção de SQL em um ORM assíncrono Python, com reprodução, análise e correção.
Ormar é um mini ORM assíncrono popular para Python, comumente usado com FastAPI e Starlette. As versões 0.9.9 até 0.22.0 contêm uma vulnerabilidade de injeção de SQL nos métodos agregados min() e max().
A causa raiz é um bug de "implementação parcial": enquanto sum() e avg() validam que o parâmetro de coluna se refere a um campo numérico real, min() e max() ignoram essa verificação completamente e passam a entrada do usuário diretamente para sqlalchemy.text() — um sumidouro de SQL bruto.
Um atacante pode injetar uma subconsulta como o parâmetro "coluna":
# Uso esperado
await Item.objects.max("price") # → SELECT max(price) FROM items
# Payload de ataque
await Item.objects.max("(SELECT password FROM users LIMIT 1)")
# → SELECT max((SELECT password FROM users LIMIT 1)) FROM items
# Retorna a senha do administrador!
| Atributo | Valor |
|---|---|
| ID CVE | CVE-2026-26198 |
| Pontuação CVSS | 9.8 (Crítico) |
| CWE | CWE-89: Injeção de SQL |
| Afetado | ormar 0.9.9 – 0.22.0 |
| Corrigido em | ormar 0.23.0 |
| Publicado | 24 de fevereiro de 2026 |
| Autenticação necessária? | Nenhuma — não autenticado |
├── README.md ← Você está aqui
├── vulnerable_app.py ← Aplicação FastAPI mínima com o padrão vulnerável
├── exploit_demo.py ← PoC seguro mostrando a injeção em ação
├── patched_app.py ← A versão corrigida com validação de entrada
├── test_vulnerability.py ← Testes provando que a vulnerabilidade existe e que a correção funciona
├── requirements.txt
└── analysis/
└── root_cause.md ← Análise detalhada do bug em nível de código
git clone https://github.com/YOUR_USERNAME/CVE-2026-26198-analysis.git
cd CVE-2026-26198-analysis
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
# Execute os testes (nenhum banco de dados externo necessário — usa SQLite)
python -m pytest test_vulnerability.py -v
# Execute a demonstração interativa do exploit
python exploit_demo.py
A correção valida que o parâmetro de coluna corresponde a um campo real no modelo antes de chegar a sqlalchemy.text(). Isso é feito por meio de uma abordagem de lista de permissões: apenas nomes de colunas que existem nas definições de campos do modelo são permitidos.
Consulte patched_app.py para a implementação e analysis/root_cause.md para a análise completa.
sum()/avg() serem validados, mas min()/max() não, criou uma falsa sensação de segurança.MIT