
Injeção de SQL em PyAthena via DefaultParameterFormatter (CVE-2026-65321)
Gravidade: Crítica, CVSS v4.0 9.3 / CVSS v3.1 9.8 (atribuída pela VulnCheck, a CNA)
Vetor (v4.0): CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Vetor (v3.1): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Afetados: PyAthena <= 3.35.3 (todas as versões até 3.35.3)
Corrigido em: 3.35.4
CWE: CWE-89 (Neutralização Incorreta de Elementos Especiais usados em um Comando SQL, 'Injeção de SQL')
Reportado por: Rahul Karne
CNA: VulnCheck
Publicado: 3 de agosto de 2026
O PyAthena escapava corretamente a entrada não confiável em consultas SELECT e
incorretamente em consultas DELETE.
O PyAthena, o amplamente utilizado cliente Python DB-API para Amazon Athena,
seleciona sua rotina de escape de strings com base na palavra-chave inicial da
instrução. Instruções que começam com SELECT, WITH, INSERT, UPDATE ou
MERGE recebem escape correto para o Trino, no qual uma aspa simples é
neutralizada pela sua duplicação (''). Qualquer outra instrução, mais
comumente um DELETE ou um CREATE TABLE … AS SELECT (CTAS), cai no escape com
barra invertida no estilo Hive (\'). O mecanismo do Athena é o Trino, que
trata uma barra invertida dentro de uma string entre aspas simples como um
caractere comum, portanto o escape com barra invertida não neutraliza nada. Um
atacante que consiga influenciar um parâmetro de string em tal instrução pode
terminar o literal e injetar SQL arbitrário, sem autenticação e sem interação do
usuário.
A falha está, portanto, ausente do caminho de leitura e presente exatamente nos tipos de instrução destrutivos onde causa mais dano. O pacote é baixado 22,3 milhões de vezes por mês.
O PyAthena é uma biblioteca cliente comunitária de terceiros para Amazon Athena. Não é um produto AWS, e esta não é uma vulnerabilidade na AWS ou no próprio Athena.
Um atacante que controle um parâmetro de string passado a uma instrução
vulnerável pode sair do literal de string pretendido e alterar a lógica da
instrução. O impacto mais direto e confiavelmente demonstrável é a exclusão
não autorizada de dados: uma carga útil como missing' OR 1=1 -- em uma
consulta DELETE … WHERE token = %(token)s neutraliza o predicado WHERE e
exclui todas as linhas que a função IAM do workgroup do Athena tem permissão de
excluir (por exemplo, todas as linhas de uma tabela Iceberg). Dependendo do tipo
de instrução e das permissões da função, um atacante também pode ser capaz de
criar tabelas definidas pelo atacante via injeção de CTAS e, onde puder
posteriormente ler a tabela resultante, exfiltrar dados de outras tabelas às
quais a função tem acesso.
Todo o impacto é limitado pelas permissões do workgroup do Athena / função IAM que o cliente utiliza. Esta é uma injeção no plano de dados no mecanismo SQL do Athena; ela não resulta em execução de código no host que executa o PyAthena, nem compromete a própria AWS.
Quem é afetado: aplicações que usam PyAthena < 3.35.4 com o
DefaultParameterFormatter padrão (substituição de parâmetros pyformat /
named no lado do cliente) que (1) constroem uma instrução que não começa com
SELECT/WITH/INSERT/UPDATE/MERGE, na prática DELETE, CTAS,
CREATE VIEW, DROP ou ALTER, e (2) passam dados influenciados pelo atacante
como um parâmetro de string para essa instrução.
Quem não é afetado:
3.35.4 ou posterior.SELECT/WITH/INSERT/UPDATE/MERGE, estas são roteadas para o escapador
seguro de duplicação de aspas.| Métrica | Valor | Fonte |
|---|---|---|
| Downloads, todos os tempos | 740,6M | pepy.tech/projects/pyathena |
| Downloads, últimos 30 dias | 22,3M | pepy.tech |
| Downloads, últimas 24 horas | 221,0K | pepy.tech |
| Taxa de instalação sustentada | 8,95/segundo | pepy.tech |
| Downstream notável | dbt-athena importa _escape_hive e _escape_presto diretamente de pyathena.formatter | connections_legacy.py#L23-L27 |
DefaultParameterFormatter.format() seleciona a função de escape de strings
puramente a partir da palavra-chave inicial da instrução. Apenas uma lista de
permissão de prefixos recebe o escapador correto para o Trino; qualquer outra
instrução cai no escape com barra invertida no estilo Hive.
# src/pyathena/formatter.py, DefaultParameterFormatter.format(), lines ~271-275 (v3.35.2)
operation_upper = operation.upper()
if operation_upper.startswith(("SELECT", "WITH", "INSERT", "UPDATE", "MERGE")):
escaper = _escape_presto # safe: doubles single quotes
else:
escaper = _escape_hive # UNSAFE for Trino: backslash-escapes quotes
# src/pyathena/formatter.py, lines ~157-165 (v3.35.2)
def _escape_hive(val: str) -> str:
escaped = (
val.replace("\\", "\\\\")
.replace("'", "\\'") # produces \' (not a quote escape in Trino)
.replace("\r", "\\r")
.replace("\n", "\\n")
.replace("\t", "\\t")
)
return f"'{escaped}'"
O mecanismo SQL da Amazon Athena é o Trino (Presto em versões anteriores do
mecanismo). No Trino, o único escape para uma aspa simples dentro de um literal
de string entre aspas simples é duplicá-la (''); uma barra invertida é um
caractere literal. Portanto, _escape_hive não neutraliza uma aspa de forma
alguma para o Athena; ele emite ... = 'missing\' OR 1=1 -- ', que o Trino
interpreta como o literal de string 'missing\' seguido por OR 1=1 -- ', ou
seja, SQL controlado pelo atacante.
O projeto é perigoso-em-falha: ele usa lista de permissão para o caminho
seguro e define como padrão tudo o mais para o escapador inseguro. A correção
upstream inverte isso para seguro-em-falha (padrão para o escapador do Trino;
usa escape Hive apenas para DDL Hive genuíno, como CREATE DATABASE/DROP TABLE/MSCK REPAIR, enquanto trata CTAS e CREATE VIEW como Trino) e,
adicionalmente, remove comentários SQL iniciais para que um prefixo /* … */ DELETE … não possa derrotar a detecção do tipo de instrução.
_escape_hive não é falta de sanitização, ele é sanitização. É uma rotina de
escape correta e bem formada para a gramática de literais de string do Hive,
aplicada a um mecanismo que usa a do Trino. Ferramentas de rastreamento de fluxo
modelam injeção de SQL como dados não confiáveis alcançando um sumidouro sem
passar por um escapador; aqui os dados passam por um escapador em todos os
caminhos, e o escapador parece exatamente com código de remediação porque é
código de remediação, para o dialeto errado.
Correção de dialeto não é uma propriedade de rastreamento de fluxo, portanto nenhuma regra de taint a avalia. O defeito é estruturalmente invisível para CodeQL, Semgrep, Snyk e Socket, em vez de meramente negligenciado por eles, e é por isso que persistiu em um pacote instalado aproximadamente nove vezes por segundo.
Um atacante precisa de: