
Advisory e reprodutor AddressSanitizer para um heap-buffer-overflow no SQLAR do SQLite, acionado por um valor SZ manipulado, causando alocação truncada e gravação fora dos limites no zlib.
O CVE-2026-39113 é um estouro de buffer no heap na extensão SQLAR opcional do SQLite. Em um aplicativo que carregou a extensão, um atacante que consiga invocar sqlar_uncompress() com um blob comprimido e um tamanho controlados pode fazer o zlib gravar além de uma alocação de heap em um sistema LP64. Esta é uma falha de limite de segurança de memória dentro do processo hospedeiro; não é um problema de análise de arquivo de banco de dados do SQLite, nem um bypass de autenticação, nem uma falha acessível em toda implantação padrão do SQLite.
O comportamento vulnerável foi introduzido em 11/03/2026 pelo commit Git 169f68e (check-in Fossil 8bdc0d485e3ad0c7...) e corrigido em 01/04/2026 pelo commit Git 34e139d (check-in Fossil 6194f3b5314ef98b...). O escopo afetado compreende snapshots de código-fonte e builds personalizados desde 169f68e até o pai de 34e139d. Nenhum lançamento oficial do SQLite foi verificado como vulnerável: o SQLite 3.52.0 é anterior à introdução, e o SQLite 3.53.0 contém tanto a alteração que introduziu o problema quanto a correção. O SQLite 3.53.0 é, portanto, o primeiro lançamento oficial a conter o código corrigido, e não um lançamento afetado.
Revisei a revisão vulnerável exata, as alterações que introduziram e corrigiram o problema e os snapshots de lançamento 3.52.0 e 3.53.0. Também inspecionei a saída preservada de uma execução autorizada em um ambiente descartável WSL2 Ubuntu 24.04. O AddressSanitizer observou um heap-buffer-overflow seguido de encerramento do processo, estabelecendo corrupção nativa do heap e negação de serviço. A execução de código não foi demonstrada.
SQLAR é um formato de arquivo do SQLite. A extensão opcional em ext/misc/sqlar.c registra sqlar_compress() e sqlar_uncompress() como funções SQL. Ela não faz parte de todos os aplicativos que usam SQLite; o caminho vulnerável exige que a extensão esteja presente e carregada.
Para este relatório, Mallory controla o blob e os argumentos SZ fornecidos a:
SELECT sqlar_uncompress(?1, ?2);
O ambiente testado tinha int de 32 bits, sqlite3_int64 e uLongf do zlib de 64 bits. A função deveria alocar pelo menos tanta memória quanto o zlib tem permissão para gravar. Em vez disso, o código-fonte vulnerável converte o tamanho de 64 bits para o tipo de parâmetro de 32 bits de sqlite3_malloc() enquanto mantém o valor completo para uncompress().
O snapshot de código-fonte vulnerável imprimiu Configuring SQLite version 3.53.0 durante a configuração. Essa string de versão de desenvolvimento não deve ser confundida com o lançamento oficial do SQLite 3.53.0 datado de 09/04/2026, cujo código-fonte contém a correção.
Na revisão avaliada, sqlarUncompressFunc() em ext/misc/sqlar.c lê o tamanho controlado pelo atacante como um inteiro de 64 bits:
sqlite3_int64 sz;
sz = sqlite3_value_int64(argv[1]);
Se sz for positivo e diferente do comprimento do blob de entrada, o mesmo valor é usado de duas maneiras incompatíveis:
uLongf szf = sz;
const Bytef *pData = sqlite3_value_blob(argv[0]);
Bytef *pOut = sqlite3_malloc(sz);
if( pOut==0 ){
sqlite3_result_error_nomem(context);
}else if( Z_OK!=uncompress(pOut, &szf, pData, nData) ){
sqlite3_result_error(context, "error in uncompress()", -1);
}
Nesta revisão, o SQLite declara sqlite3_malloc(int). No build LP64 testado, o valor do PoC 4294967328 (0x100000020) tornou-se 32 ao ser passado para essa API, enquanto szf manteve o valor completo de 64 bits. O SQLite, portanto, fez uma alocação pequena, mas o zlib foi informado de que o buffer de saída poderia conter mais de 4 GiB. A descompressão de um blob de 42 bytes representando 4096 bytes de dados então cruzou o limite da alocação.
A incompatibilidade entrou no projeto quando a alteração de 11/03/2026 substituiu sqlite3_value_int() por sqlite3_value_int64() sem alterar a API de alocação. A revisão do código-fonte do SQLite 3.52.0 mostra a leitura anterior de 32 bits, portanto a incompatibilidade largura total/alocação curta não estava presente ali. A correção de 01/04/2026 alterou a alocação para sqlite3_malloc64(sz). A revisão do código-fonte da tag oficial 3.53.0 confirma essa chamada corrigida.
A primitiva demonstrada é uma gravação de heap fora dos limites no processo que hospeda o SQLite. A execução preservada mostra o AddressSanitizer detectando a primeira gravação inválida de um byte imediatamente após uma região de heap de 40 bytes alocada por meio de sqlite3_malloc(), seguida de um abort. Isso suporta diretamente o crash do processo e a negação de serviço.
A exploração exige todos os seguintes requisitos:
sqlar_uncompress() com um blob e um valor SZ controlados;int tem 32 bits enquanto sqlite3_int64 e uLongf do zlib têm 64 bits; eO PoC controla os bytes descomprimidos, o que é relevante para a gravidade da corrupção nativa do heap. No entanto, transformar essa primitiva em execução de código dependeria do layout do alocador, do estado circundante do processo, das mitigações e de uma rota adequada no nível do aplicativo. Nenhuma cadeia desse tipo foi testada ou demonstrada, portanto este relatório não afirma execução de código.
A execução preservada não incluiu um controle negativo em tempo de execução contra a revisão corrigida. Dois controles no nível do código-fonte restringem a explicação: o SQLite 3.52.0 lê o tamanho com a API de 32 bits, e o código-fonte oficial 3.53.0 aloca com sqlite3_malloc64(). Essas verificações suportam a introdução e a correção identificadas, mas não são apresentadas como testes executados contra o alvo corrigido. A prevalência de aplicativos que carregam essa extensão opcional é desconhecida.
O repositório inclui:
poc/verify_sqlar_poc.c, que cria um payload de 4096 bytes, o comprime, carrega sqlar.so e define SZ = 4294967328;poc/reproduce.sh, que clona revisões fixadas (pinned) do SQLite e do zlib, as compila com AddressSanitizer, compila a extensão e o harness e executa o gatilho; eevidence/asan-summary.txt, um resumo com caminhos normalizados da execução autorizada observada.Execute o reprodutor apenas em um ambiente Linux ou WSL descartável. Ele aciona intencionalmente corrupção de memória e um abort do AddressSanitizer. O script exige git, make, um compilador C, ferramentas de build padrão e acesso à rede:
chmod +x poc/reproduce.sh
./poc/reproduce.sh
O reprodutor foi executado novamente em 21/08/2026 no Ubuntu 24.04 sob WSL2 e produziu o mesmo achado do AddressSanitizer. Sua saída relevante foi:
env: sizeof(int)=4 sizeof(sqlite3_int64)=8 sizeof(uLongf)=8
payload: plain=4096 compressed=42 evil_sz=4294967328 low32=32
ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 1
#0 inflate_fast zlib/inffast.c:252
#4 uncompress zlib/uncompr.c:100
#5 sqlarUncompressFunc sqlite/ext/misc/sqlar.c:97
The write occurred immediately after a 40-byte heap region.
SUMMARY: AddressSanitizer: heap-buffer-overflow in inflate_fast
ABORTING
PoC exit status: 1
Essa saída mostra as larguras de tipo incompatíveis e o tamanho forjado, a gravação do zlib, a chamada de sqlarUncompressFunc() e a violação do limite da alocação. O script de reprodução exclui seu diretório temporário de build na saída, a menos que KEEP_BUILD=1 esteja definido.
O upstream corrigiu a alocação vulnerável no commit 34e139d:
- Bytef *pOut = sqlite3_malloc(sz);
+ Bytef *pOut = sqlite3_malloc64(sz);
Isso mantém a largura da alocação consistente com o valor positivo sz de 64 bits retido em uLongf szf e passado ao zlib. O código corrigido está presente no SQLite 3.53.0 oficial. Usuários de snapshots de código-fonte ou builds personalizados que contenham o intervalo vulnerável devem atualizar para 34e139d ou posterior. Aplicativos que não exigem SQLAR devem evitar carregar a extensão, e aplicativos que a usam devem impedir que chamadores não confiáveis forneçam argumentos arbitrários a sqlar_uncompress().
Um teste de regressão direcionado deve exercitar a função SQL com um blob comprimido válido e um valor SZ acima de INT_MAX cujos 32 bits baixos sejam pequenos. Ele deve verificar se o build corrigido não realiza uma alocação truncada e deve manter os casos de descompressão bem-sucedida comum e de erro por entrada inválida como controles.
O CVE-2026-39113 afeta apenas snapshots de código-fonte e builds personalizados do SQLite desde 169f68e até o pai de 34e139d quando a extensão SQLAR opcional está carregada e chamadas controladas pelo atacante alcançam sqlar_uncompress() em um build LP64. Um tamanho de 64 bits foi reduzido por sqlite3_malloc(int) enquanto o zlib mantinha o valor completo, produzindo um heap-buffer-overflow confirmado pelo AddressSanitizer e um abort do processo. Nenhum lançamento oficial do SQLite foi verificado como vulnerável, e a execução de código não foi demonstrada. A alteração do upstream para sqlite3_malloc64(sz) está presente no SQLite 3.53.0 oficial e remove a incompatibilidade de largura da alocação.