
Advisory et reproducteur AddressSanitizer pour un heap-buffer-overflow dans le SQLAR de SQLite, déclenché par une valeur SZ contrefaite entraînant une allocation tronquée et une écriture hors limites dans zlib.
CVE-2026-39113 est un débordement de tampon dans le tas au sein de l'extension SQLAR optionnelle de SQLite. Dans une application ayant chargé l'extension, un attaquant capable d'invoquer sqlar_uncompress() avec un blob compressé contrôlé et une taille contrôlée peut amener zlib à écrire au-delà d'une allocation de tas sur un système LP64. Il s'agit d'une défaillance de la frontière de sécurité mémoire au sein du processus hôte ; ce n'est ni un problème d'analyse des fichiers de base de données SQLite, ni un contournement d'authentification, ni une faille accessible dans chaque déploiement SQLite par défaut.
Le comportement vulnérable a été introduit le 11/03/2026 par le commit Git 169f68e (check-in Fossil 8bdc0d485e3ad0c7...) et corrigé le 01/04/2026 par le commit Git 34e139d (check-in Fossil 6194f3b5314ef98b...). Le périmètre affecté comprend les instantanés du code source et les compilations personnalisées allant de 169f68e jusqu'au parent de 34e139d. Aucune version officielle de SQLite n'a été vérifiée comme vulnérable : la version SQLite 3.52.0 est antérieure à l'introduction de la faille, et la version SQLite 3.53.0 contient à la fois la modification ayant introduit la faille et le correctif. SQLite 3.53.0 est donc la première version officielle contenant le code corrigé, et non une version affectée.
J'ai examiné la révision vulnérable exacte, les modifications ayant introduit et corrigé la faille, ainsi que les instantanés des versions 3.52.0 et 3.53.0. J'ai également inspecté la sortie conservée d'une exécution autorisée dans un environnement jetable WSL2 Ubuntu 24.04. AddressSanitizer a détecté un débordement de tampon dans le tas suivi de la terminaison du processus, établissant une corruption native du tas et un déni de service. L'exécution de code n'a pas été démontrée.
SQLAR est un format d'archive SQLite. L'extension optionnelle dans ext/misc/sqlar.c enregistre sqlar_compress() et sqlar_uncompress() comme fonctions SQL. Elle ne fait pas partie de toutes les applications utilisant SQLite ; le chemin vulnérable nécessite que l'extension soit présente et chargée.
Pour ce rapport, Mallory contrôle le blob et les arguments SZ fournis à :
SELECT sqlar_uncompress(?1, ?2);
L'environnement testé disposait d'un int sur 32 bits, d'un sqlite3_int64 sur 64 bits et d'un uLongf de zlib sur 64 bits. La fonction devrait allouer au moins autant de mémoire que zlib est autorisé à écrire. Au lieu de cela, le code source vulnérable convertit la taille 64 bits vers le type de paramètre 32 bits de sqlite3_malloc() tout en conservant la valeur complète pour uncompress().
L'instantané du code source vulnérable affichait Configuring SQLite version 3.53.0 lors de la configuration. Cette chaîne de version de développement ne doit pas être confondue avec la version officielle SQLite 3.53.0 datée du 09/04/2026, dont le code source contient le correctif.
À la révision évaluée, sqlarUncompressFunc() dans ext/misc/sqlar.c lit la taille contrôlée par l'attaquant comme un entier 64 bits :
sqlite3_int64 sz;
sz = sqlite3_value_int64(argv[1]);
Si sz est positif et diffère de la longueur du blob d'entrée, la même valeur est utilisée de deux manières incompatibles :
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);
}
À cette révision, SQLite déclare sqlite3_malloc(int). Sur la compilation LP64 testée, la valeur PoC 4294967328 (0x100000020) est devenue 32 lorsqu'elle a été transmise à cette API, tandis que szf conservait la valeur 64 bits complète. SQLite a donc effectué une petite allocation, mais zlib a été informé que le tampon de sortie pouvait contenir plus de 4 Gio. La décompression d'un blob de 42 octets représentant 4096 octets de données a alors franchi la limite de l'allocation.
L'incohérence a été introduite dans le projet lorsque la modification du 11/03/2026 a remplacé sqlite3_value_int() par sqlite3_value_int64() sans modifier l'API d'allocation. L'examen du code source de SQLite 3.52.0 montre l'ancienne lecture 32 bits ; l'incohérence pleine largeur/allocation courte n'y était donc pas présente. Le correctif du 01/04/2026 a remplacé l'allocation par sqlite3_malloc64(sz). L'examen du code source du tag officiel 3.53.0 confirme cet appel corrigé.
La primitive démontrée est une écriture hors limites dans le tas au sein du processus hébergeant SQLite. L'exécution conservée montre AddressSanitizer détectant la première écriture invalide d'un octet immédiatement après une région de tas de 40 octets allouée via sqlite3_malloc(), suivie d'un abandon. Cela étaye directement un crash du processus et un déni de service.
L'exploitation nécessite toutes les conditions suivantes :
sqlar_uncompress() avec un blob contrôlé et une valeur SZ contrôlée ;int est sur 32 bits tandis que sqlite3_int64 et uLongf de zlib sont sur 64 bits ; etLe PoC contrôle les octets décompressés, ce qui est pertinent pour la gravité de la corruption native du tas. Cependant, transformer cette primitive en exécution de code dépendrait de la disposition de l'allocateur, de l'état du processus environnant, des mesures d'atténuation et d'une voie appropriée au niveau applicatif. Aucune chaîne de ce type n'a été testée ni démontrée ; ce rapport ne revendique donc pas l'exécution de code.
L'exécution conservée n'incluait pas de contrôle négatif à l'exécution contre la révision corrigée. Deux contrôles au niveau du code source affinent l'explication : SQLite 3.52.0 lit la taille avec l'API 32 bits, et le code source officiel 3.53.0 alloue avec sqlite3_malloc64(). Ces vérifications appuient l'introduction et le correctif identifiés, mais ne sont pas présentées comme des tests exécutés contre la cible corrigée. La prévalence des applications chargeant cette extension optionnelle est inconnue.
Le dépôt comprend :
poc/verify_sqlar_poc.c, qui crée une charge utile de 4096 octets, la compresse, charge sqlar.so et lie SZ = 4294967328 ;poc/reproduce.sh, qui clone des révisions épinglées de SQLite et de zlib, les compile avec AddressSanitizer, compile l'extension et le harnais de test, puis exécute le déclencheur ; etevidence/asan-summary.txt, un résumé de l'exécution autorisée observée, dont les chemins ont été normalisés.Exécutez le reproducteur uniquement dans un environnement Linux ou WSL jetable. Il déclenche intentionnellement une corruption mémoire et un abandon d'AddressSanitizer. Le script nécessite git, make, un compilateur C, les outils de compilation standard et un accès réseau :
chmod +x poc/reproduce.sh
./poc/reproduce.sh
Le reproducteur a été exécuté de nouveau le 21/08/2026 sur Ubuntu 24.04 sous WSL2 et a produit la même détection AddressSanitizer. La sortie pertinente était :
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
Cette sortie montre les largeurs de types incompatibles et la taille forgée, l'écriture de zlib, l'appel depuis sqlarUncompressFunc() et la violation de la limite d'allocation. Le script de reproduction supprime son répertoire de compilation temporaire à la sortie, sauf si KEEP_BUILD=1 est défini.
Le projet en amont a corrigé l'allocation vulnérable dans le commit 34e139d :
- Bytef *pOut = sqlite3_malloc(sz);
+ Bytef *pOut = sqlite3_malloc64(sz);
Cela maintient la largeur de l'allocation cohérente avec la valeur positive 64 bits sz conservée dans uLongf szf et transmise à zlib. Le code corrigé est présent dans la version officielle SQLite 3.53.0. Les utilisateurs d'instantanés du code source ou de compilations personnalisées contenant l'intervalle vulnérable doivent mettre à jour vers 34e139d ou une version ultérieure. Les applications qui n'ont pas besoin de SQLAR devraient éviter de charger l'extension, et les applications qui l'utilisent devraient empêcher les appelants non fiables de fournir des arguments arbitraires à sqlar_uncompress().
Un test de régression ciblé devrait exercer la fonction SQL avec un blob compressé valide et une valeur SZ supérieure à INT_MAX dont les 32 bits de poids faible sont petits. Il devrait vérifier que la compilation corrigée n'effectue pas d'allocation tronquée et devrait conserver les cas de décompression réussie normale et d'erreur sur entrée invalide comme témoins.
CVE-2026-39113 n'affecte que les instantanés du code source et les compilations personnalisées de SQLite allant de 169f68e jusqu'au parent de 34e139d, lorsque l'extension SQLAR optionnelle est chargée et que des appels contrôlés par l'attaquant atteignent sqlar_uncompress() sur une compilation LP64. Une taille 64 bits a été réduite par sqlite3_malloc(int) tandis que zlib conservait la valeur complète, produisant un débordement de tampon dans le tas confirmé par AddressSanitizer et un abandon du processus. Aucune version officielle de SQLite n'a été vérifiée comme vulnérable, et l'exécution de code n'a pas été démontrée. La modification en amont vers sqlite3_malloc64(sz) est présente dans la version officielle SQLite 3.53.0 et supprime l'incohérence de largeur d'allocation.