CVE-2026-26030 : l'injection de prompt devient RCE dans Microsoft Semantic Kernel
L'AI Red Team de Microsoft a montré deux failles de Semantic Kernel qui transforment un simple prompt injecté en exécution de code sur l'hôte. La leçon : tout paramètre d'outil influençable par le modèle est une entrée contrôlée par l'attaquant. Corrigé le 7 mai 2026.
De quoi s’agit-il ?
Le 7 mai 2026, l’équipe de recherche sécurité de Microsoft Defender (Uri Oren, Amit Eliahu, Dor Edry) a publié « When prompts become shells », documentant deux vulnérabilités critiques dans Microsoft Semantic Kernel — le framework d’agents open source de l’éditeur, plus de 27 000 étoiles sur GitHub et la même filiation que Copilot Studio. Les failles, CVE-2026-26030 (SDK Python) et CVE-2026-25592 (SDK .NET), permettent de transformer une injection de prompt ordinaire en exécution de code à distance sur l’hôte qui héberge l’agent. La fiche NVD note CVE-2026-26030 à CVSS 9.8. Les deux ont été divulguées de façon responsable au MSRC et corrigées le jour même de la publication.
L’enseignement est structurel, pas accidentel : dès qu’un modèle est relié à des outils, la frontière entre « problème de contenu » et « primitive d’exécution » disparaît. Le modèle fait exactement ce pour quoi il est conçu — traduire le langage en appels d’outils. La vulnérabilité tient à la façon dont le framework fait confiance aux paramètres analysés.
Comment ça marche
CVE-2026-26030 — le sink eval() (Python). Le Vector Store en mémoire par défaut de Semantic Kernel construit son filtre sous forme de lambda Python et l’exécute via eval(). Pour un agent de recherche d’hôtels, une requête comme « Trouve des hôtels à Paris » devient lambda x: x.city == 'Paris'. La valeur city est contrôlée par le modèle et non assainie — un sink d’injection classique. En fermant la chaîne et en ajoutant du Python, un attaquant peut sortir de l’expression. Le framework l’avait anticipé via une liste de blocage basée sur l’AST qui rejetait les noms comme eval, exec, open et __import__ et supprimait __builtins__. Microsoft a montré que cette liste était contournable : une charge enveloppée dans une lambda valide passait le contrôle structurel et, plutôt que des noms bloqués, parcourait la hiérarchie de classes de Python (via tuple, __class__, __subclasses__, BuiltinImporter) pour atteindre os.system — aucun n’étant dans la liste. Aucune charge fonctionnelle n’est reproduite ici ; la leçon tient sans elle.
CVE-2026-25592 — l’outil trop exposé (.NET). Le SessionsPythonPlugin exécute le code généré par le modèle dans un bac à sable Azure Container Apps isolé. Mais DownloadFileAsync — une fonction côté hôte — était par erreur annotée [KernelFunction], ce qui l’exposait au modèle comme un outil appelable. Son paramètre localFilePath, qui décide où File.WriteAllBytes() écrit sur l’hôte, était donc contrôlé par le modèle, sans validation de chemin. En enchaînant « écrire la charge dans le bac à sable » et « la télécharger vers le dossier Démarrage de l’hôte », on obtient une évasion du bac à sable vers une RCE complète à la prochaine connexion. Microsoft rattache la chaîne à MITRE ATLAS AML.T0051 (LLM Prompt Injection) cascadant vers AML.T0016 (Obtain Capabilities).
Pourquoi c’est important
Les deux bugs partagent la même erreur d’architecture : faire confiance à une entrée routée par le modèle suffisamment loin pour qu’elle atteigne une primitive d’évaluation de code ou de système de fichiers. Quand la récupération alimente les arguments d’outils et que ces arguments alimentent un interpréteur, la frontière entre contenu récupéré et code exécutable se dissout — et l’assainissement d’entrée classique, situé hors du runtime de l’agent, ne voit jamais la charge.
Le rayon d’impact est large. Semantic Kernel fait tourner des applications RAG en production sur Azure, des scénarios Microsoft 365 Copilot et une longue traîne d’automatisations internes dans des secteurs régulés. Pour CVE-2026-26030, le seul prérequis est qu’un champ influencé par l’attaquant atteigne l’index — un seul document empoisonné dans un corpus partagé peut toucher tous les agents en aval qui l’interrogent. Comme le dit Microsoft sans détour : votre LLM n’est pas une frontière de sécurité ; les outils que vous exposez définissent le périmètre de l’attaquant.
Défenses
- Corrigez maintenant. Passez le paquet Python
semantic-kernelen 1.39.4+ et le SDK .NET en 1.71.0+. Inutile de réécrire l’agent — les correctifs retirent au modèle la capacité de déclencher ces fonctions de façon autonome. - Préférez les listes d’autorisation aux listes de blocage au niveau des sinks d’évaluation. Le correctif de Semantic Kernel a remplacé la liste de blocage fragile par une liste d’autorisation de types de nœuds AST, une liste d’appels autorisés, une liste de blocage d’attributs de parcours de hiérarchie (
__class__,__subclasses__) et une restriction de noms. Dans les langages dynamiques, interdire les jetons dangereux est structurellement perdant ; seule l’autorisation explicite des constructions sûres tient. - Traitez tout paramètre d’outil influencé par le modèle comme une entrée non fiable. Validez et canonicalisez les chemins de fichiers (
Path.GetFullPath()plus une liste de répertoires autorisés), paramétrez les requêtes, et n’interpolez jamais la sortie du modèle dans du codeeval/exec/templaté. - N’exposez pas les fonctions dangereuses comme outils. Auditez quelles fonctions portent une annotation
[KernelFunction]/ schéma d’outil. Les fonctions côté hôte de fichier, de processus et de réseau ne devraient être appelables que par votre code, jamais par le modèle — voir l’empoisonnement de descriptions d’outils, surface non testée. - Défendez aussi au niveau de l’hôte. Le garde-fou du modèle pouvant être contourné, corrélez les signaux au niveau modèle avec la télémétrie endpoint : un processus hôte d’agent qui lance
cmd.exe/powershell.exeou dépose des fichiers dans le dossier Démarrage est un signal fort de post-exploitation. Microsoft a publié des requêtes de chasse avancée pour exactement cela. - Appliquez le moindre privilège à l’agent. La règle de deux des agents et le moindre privilège par outil limitent ce qu’une injection réussie peut atteindre.
Statut
| Élément | Détail |
|---|---|
| CVE | CVE-2026-26030 (Python), CVE-2026-25592 (.NET) |
| Composant | Semantic Kernel — filtre du Vector Store en mémoire ; SessionsPythonPlugin |
| Classe | Injection de prompt → sink eval() RCE ; outil trop exposé → écriture de fichier hôte / évasion de bac à sable |
| CVSS | 9.8 (CVE-2026-26030, NVD) |
| Affecté | Python semantic-kernel < 1.39.4 ; SDK .NET < 1.71.0 |
| Corrigé dans | Python 1.39.4 ; .NET 1.71.0 |
| Divulgation | Coordonnée via MSRC ; corrigé le jour de la publication (7 mai 2026) |
| Dans la nature | PoC reproductible par Microsoft ; aucune campagne confirmée à la divulgation |
Ce n’est pas vraiment « un bug de Semantic Kernel ». C’est la réécriture, à l’ère des agents, d’une vieille leçon de sécurité web : une entrée non fiable ne doit jamais atteindre une opération à haut risque sans médiation. Dans les années 2000, cette entrée allait dans des requêtes SQL et des appels shell ; aujourd’hui elle arrive en langage naturel, est analysée en arguments d’outils et atterrit dans un interpréteur. Microsoft a annoncé que les prochains volets de cette série de recherche couvriront des bugs d’exécution structurellement identiques dans d’autres frameworks largement utilisés — traitez donc cela comme une classe, pas un cas isolé, et supposez que tout framework qui mappe la sortie d’un modèle vers des outils système partage la même forme.