La faille Wasm : s'évader des sandbox WebAssembly backend

Dans le paysage cloud-native moderne, WebAssembly (Wasm) est passé d’un accélérateur de performance côté navigateur à la « prochaine génération de conteneur » pour le backend. Des fonctions serverless aux pipelines d’inférence AI haute performance et traitement d’images, Wasm offre une alternative légère et à démarrage rapide aux conteneurs Docker traditionnels.
Le principal argument de vente de Wasm est son sandbox. Il est présenté comme « sûr par conception », isolé de l’environnement hôte via une interface strictement contrôlée (WASI) et un modèle de mémoire sans partage. Cependant, à mesure que la complexité des runtimes backend augmente, une nouvelle surface d’attaque sophistiquée émerge.
Ce plongée approfondie explore comment la sécurité théorique de WebAssembly est remise en question par des vulnérabilités de « Mémoire Linéaire » et des bugs dans la logique du JIT-compiler, permettant à des modules malveillants de « percer » le sandbox et d’obtenir une compromission complète du système.
1. L’architecture de la cage virtuelle
Pour comprendre la faille, il faut d’abord comprendre les murs. Contrairement à une VM ou un conteneur Docker qui s’appuie sur la virtualisation assistée par matériel ou les espaces de noms du noyau, WebAssembly repose sur l’Isolation par Faults Logiciels (SFI).
Le modèle de mémoire linéaire
Un module Wasm n’a pas accès à la mémoire de l’hôte. À la place, il reçoit une « Mémoire Linéaire » — un bloc contigu de bytes bruts.
Isolation : Chaque instruction de chargement ou de stockage en Wasm est relative au début de ce bloc.
Vérification des limites : Le runtime (ex. Wasmtime, Wasmer, V8) doit vérifier que chaque accès reste dans la plage de 0 à max_memory.
Le rôle du JIT-compiler
Pour atteindre des vitesses proches du natif, les runtimes utilisent des compilateurs Just-In-Time (JIT) comme Cranelift (utilisé par Wasmtime) ou LLVM. Ces compilateurs traduisent le bytecode Wasm en assembleur au niveau machine. Pour optimiser la performance, ils peuvent omettre (sauter) les vérifications explicites de limites si elles peuvent « prouver » que l’accès sera toujours sûr. Cette optimisation constitue la faille où de nombreuses escapades commencent.
2. Percer le sandbox : vulnérabilités de la mémoire linéaire
La misconception la plus courante sur Wasm est qu’il « empêche » les dépassements de tampon. Ce n’est pas le cas ; il les contient simplement.
Corruption de mémoire intra-sandbox
Lorsque vous compilez un langage non sécurisé en mémoire comme C ou C++ vers Wasm, le binaire résultant reste vulnérable aux classiques débordements et bugs Use-After-Free (UAF). Cependant, ces bugs sont confinés à la mémoire linéaire du module.
La recherche : Dans le papier fondamental « Everything Old is New Again », des chercheurs ont démontré que, parce que Wasm ne possède pas de mitigations natives courantes comme les Stack Canaries ou l’ASLR (Address Space Layout Randomization) dans la mémoire linéaire, l’exploitation interne est en réalité plus facile qu’en natif x86.
Shadow Stacks : Wasm dispose d’une « pile gérée » pour les adresses de retour (qui est sûre), mais gère souvent sa propre « pile non gérée » pour les variables locales dans la mémoire linéaire. Un attaquant peut overflow un tampon sur cette pile non gérée pour écraser des pointeurs de fonction ou des données sensibles ailleurs dans le tas du module.
La fuite : accès à la mémoire hôte
Le danger réel survient lorsqu’un module échappe complètement à la mémoire linéaire. Cela se produit généralement via deux vecteurs :
A. Échecs de page de garde
Pour éviter de vérifier chaque accès mémoire (ce qui serait lent), les runtimes utilisent souvent une stratégie de « Page de garde ». Ils réservent un espace d’adresses virtuelles massif de 4 Go (ou plus), mais ne mappent la mémoire Wasm réelle qu’au début. Si un accès touche la zone « non mappée », le matériel déclenche une faute de segmentation, que le runtime intercepte.
La faille : Si un compilateur JIT permet une instruction avec un décalage extrêmement grand (ex. load [base + 5GB]), l’accès peut sauter la Page de garde et atterrir directement dans une autre partie de la mémoire du processus hôte.
B. Confusion de type et contournements de table
Wasm utilise des tables pour stocker des pointeurs de fonction pour les appels indirects (call_indirect).
Cas d’étude : CVE-2023-2033 & Contournement du sandbox V8 : En 2023, une vulnérabilité exploitée en « wild » ciblait une confusion de type dans le moteur V8 de Google. En confondant les types d’objets dans le runtime, des attaquants ont pu écraser un pointeur brut dans la WasmIndirectFunctionTable. Comme ce pointeur était utilisé par l’hôte pour naviguer dans le module, sa corruption permettait au module de pointer ses cibles « call » en dehors du sandbox, menant à des primitives d’écriture arbitraire sur l’hôte.
3. La menace invisible : bugs dans la logique du JIT-compiler
Si le runtime est le gardien et le sandbox la cellule, le JIT-compiler est l’architecte. Une erreur de logique dans le plan de l’architecte peut invalider toutes les garanties de sécurité.
Élimination des vérifications de limites (BCE)
Les compilateurs effectuent une analyse de plage pour supprimer les vérifications redondantes. Par exemple :
// Pseudocode Wasm
if (index < 100) {
return memory[index]; // Le compilateur supprime la vérification de limite ici à cause du 'if'
}
Si le bug de « sign-extension » ou une mauvaise estimation de la plage d’un entier est présent dans le JIT, il peut conclure à tort qu’une variable est sûre alors qu’elle permet en réalité un accès hors limites.
Corruption de registres
Les JIT modernes sont extrêmement complexes. Un bug dans l’allocation des registres peut causer l’écrasement d’un pointeur « sûr » par une valeur « non fiable » lors d’un changement de contexte dans le code généré par le JIT. Cela crée une fenêtre de type « Time-of-Check to Time-of-Use » (TOCTOU) où le runtime a vérifié une adresse, mais le CPU en a exécuté une autre.
4. Études de cas réelles (2024-2025)
La sécurité n’est pas théorique. Plusieurs vulnérabilités de haut profil ont récemment prouvé que les runtimes Wasm backend sont sous surveillance active.
CVE-2024-30266 : Wasmtime Confusion de type
Au début 2024, une régression a été trouvée dans la gestion d’externref (une façon pour Wasm de tenir des références à des objets hôtes). Un module pouvait provoquer une confusion du runtime entre un objet géré par l’hôte et un entier brut, menant à un panic côté hôte ou une fuite mémoire potentielle.
CVE-2023-51661 : Contournement du sandbox Wasmer
Un défaut dans le runtime Wasmer permettait à des modules Wasm malveillants de contourner les restrictions du système de fichiers WASI. En exploitant la traduction des chemins virtuels en chemins hôtes, un attaquant pouvait accéder à des fichiers sensibles (ex. /etc/passwd) qui devraient rester invisibles dans le sandbox.
Le risque d’inférence AI
Alors que les organisations déplacent l’exécution de modèles AI (avec WasmEdge ou Wasmtime-NN) vers le edge, la surface d’attaque s’élargit. Les modèles AI sont essentiellement du « code en tant que donnée ». Un fichier de modèle malveillant pourrait être conçu pour déclencher un bug spécifique du JIT lors de la phase de « compilation » des poids et opérateurs du modèle, menant à une compromission du serveur d’inférence.
5. Défense en profondeur : sécuriser le backend
Si le sandbox est perforable, comment le défendre ? L’industrie évolue vers un modèle de sécurité multicouche.
1. Vérification formelle (ISLE)
L’Alliance Bytecode a pionnérisé l’utilisation d’ISLE (Instruction Selection Link Edition) dans le compilateur Cranelift. ISLE utilise un langage spécifique au domaine pour définir des règles de compilation qui peuvent être vérifiées formellement. Cela garantit que la traduction de Wasm en code machine est mathématiquement prouvée correcte, éliminant toute classe de bugs dans le JIT.
2. Le « Heap sandbox » de V8
Le moteur V8 de Google a introduit une approche de « sandbox dans un sandbox ». Même si un attaquant parvient à un bug de corruption mémoire dans V8, il se retrouve piégé dans un « heap virtuel » secondaire qui ne contient pas de pointeurs bruts vers le reste du processus hôte (Chrome ou Node.js). Cela rend la « fuite » beaucoup plus difficile.
3. Le modèle de composants WebAssembly
Au lieu d’un seul gros « blob » Wasm monolithique, le modèle de composants encourage la division des applications en petits composants isolés. Chaque composant possède sa propre mémoire linéaire et ses propres « permissions minimales ». Si un composant de traitement d’image est compromis, il ne peut pas accéder à la mémoire ou aux capacités du composant de connexion à la base de données.
6. Résumé SEO & points clés
Pour les développeurs et architectes sécurité, la « faille Wasm » rappelle qu’aucun sandbox n’est absolu.
Mémoire Linéaire est un tampon : Considérez le code mémoire non sécurisé (C/C++) dans Wasm comme « fiable mais vérifié ». Utilisez des langages comme Rust pour minimiser la corruption intra-sandbox.
Le JIT est le maillon faible : Mettez toujours à jour vos runtimes (Wasmtime, Wasmer, V8). Les bugs du compilateur JIT sont le principal vecteur d’évasion du sandbox.
Limitez les capacités : Utilisez WASI pour définir strictement ce que le module peut toucher. N’accordez pas un accès « complet » au système de fichiers ou au réseau si ce n’est pas nécessaire.
Surveillez les runtimes : Utilisez des outils capables de détecter les « Wasm Bombs » (épuisement des ressources) ou des patterns d’appels hôtes inhabituels.
Conclusion
WebAssembly est sans doute la méthode la plus sûre pour exécuter du code non fiable aujourd’hui, mais la « faille Wasm » prouve qu’à mesure que nous déplaçons plus de calculs lourds vers le backend, les enjeux augmentent. En comprenant les mécanismes d’évasion de mémoire linéaire et les bugs du JIT, les développeurs peuvent construire des systèmes plus résilients qui ne se fient pas uniquement au sandbox, mais le renforcent avec des stratégies de défense en profondeur.
La cage est solide, mais les architectes doivent rester vigilants. 📦🛡️
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.