Pourquoi un Top 10 spécifique aux LLM ?
Le Top 10 OWASP historique repose sur une hypothèse simple : les instructions et les données circulent sur des canaux distincts. Le code est du code, l'entrée utilisateur est une chaîne que l'on valide, échappe et paramètre. Les grands modèles de langage cassent cette hypothèse au niveau architectural. Prompt système, document récupéré par le RAG, résultat d'un outil et question de l'utilisateur arrivent dans un seul flux de tokens. Le modèle n'a aucun moyen structurel de distinguer ce qui fait autorité.
C'est la raison d'être du OWASP Top 10 for LLM Applications, publié par le GenAI Security Project en 2023 puis largement remanié en 2025. Cette révision mérite une lecture attentive : certaines entrées de 2023 ont disparu (le vol de modèle, la sur-confiance comme item autonome) au profit de risques devenus visibles seulement après la mise en production de vraies chaînes RAG et de vrais agents — fuite du prompt système, faiblesses des bases vectorielles, consommation non bornée.
La liste 2025 et le contrôle qui compte vraiment
| ID | Risque | À quoi ça ressemble en prod | Contrôle à plus fort levier |
|---|---|---|---|
| LLM01 | Prompt Injection | Une page web indexée ou un ticket de support porte des instructions cachées que l'agent exécute | Outils au moindre privilège, confirmation humaine sur les effets de bord, frontières de confiance par source |
| LLM02 | Divulgation d'informations sensibles | Secrets ou données d'un autre tenant qui ressortent dans une complétion | Rédaction avant inference, retrieval sensible aux permissions, scan des sorties |
| LLM03 | Chaîne d'approvisionnement | Poids non épinglés, pickle malveillant, adaptateur LoRA compromis | Registre interne, vérification de signature, politique safetensors uniquement |
| LLM04 | Empoisonnement des données et du modèle | Corpus de fine-tuning pollué, backdoor dans un adaptateur | Provenance des jeux de données, traçabilité du lineage, évaluations anti-backdoor |
| LLM05 | Traitement non sûr des sorties | Sortie du modèle exécutée en SQL, shell, HTML ou lien Markdown | Toute complétion est une entrée non fiable : encoder, valider, allowlister |
| LLM06 | Agentivité excessive | Agent disposant d'un accès en écriture au CRM, à une boîte mail et à un cluster | Jetons cloisonnés par outil, pas de verbes destructifs, workflow d'approbation |
| LLM07 | Fuite du prompt système | Extraction du prompt révélant règles métier et endpoints internes | Aucun secret ni logique d'autorisation dans le prompt |
| LLM08 | Faiblesses vecteurs et embeddings | Fuite inter-tenants dans une collection partagée, inversion d'embedding | Isolation par tenant, filtres appliqués à la requête, réindexation sur changement d'ACL |
| LLM09 | Désinformation | Hallucinations assurées consommées par un process automatisé en aval | Ancrage avec citations, seuils de confiance, revue humaine sur les cas à fort impact |
| LLM10 | Consommation non bornée | Boucles d'agent récursives qui brûlent le budget tokens d'un trimestre en un week-end | Budgets de tokens par tenant, limites dures d'étapes, alerting sur la dépense |
La prompt injection n'est pas un bug que l'on corrige
L'erreur la plus répandue consiste à traiter LLM01 comme un problème de filtrage. On branche un classifieur de jailbreak, on constate qu'il bloque les ignore previous instructions les plus naïfs, et on considère le sujet clos. Puis quelqu'un dissimule des instructions dans un PDF, un commentaire Jira, un commentaire HTML d'une page crawlée ou une chaîne base64 au milieu d'un bloc de code — et l'agent exfiltre gaiement le contexte via l'URL d'une image Markdown.
L'injection indirecte est un problème d'architecture. La bonne question n'est pas « comment empêcher l'injection ? » mais « que se passe-t-il de pire quand elle réussit ? ». Si la réponse est « l'agent supprime des enregistrements de production » ou « l'agent envoie un mail contenant le contexte récupéré vers une adresse contrôlée par l'attaquant », aucun filtre ne vous sauvera. Il faut concevoir comme on conçoit face à un pod compromis : périmètre minimal, pas de credentials ambiants, allowlist de sortie réseau, et actions irréversibles derrière un humain ou une politique signée.
Sorties et agentivité : là où les incidents se produisent réellement
LLM05 et LLM06 se renforcent mutuellement. Une complétion exécutée sans validation, combinée à un agent porteur de droits larges, c'est l'équivalent GenAI d'une application web tournant en root avec du SQL concaténé.
# Anti-pattern : la sortie du modèle est exécutée telle quelle
sql = llm.invoke(f"Traduis en SQL : {question}")
db.execute(sql) # une injection indirecte suffit à tout extraire
# Pattern : intention structurée + allowlist + autorisation côté serveur
intent = llm.with_structured_output(QueryIntent).invoke(question)
if intent.table not in TABLES_AUTORISEES:
raise PermissionError(intent.table)
rows = repo.select(
table=intent.table,
filters=intent.filters, # typés et validés
tenant_id=session.tenant_id, # jamais fourni par le modèle
limit=min(intent.limit, 500),
)La règle tient en une phrase : le modèle choisit l'intention, votre code détient l'autorité. Tout ce qu'émet le modèle — SQL, chemin de fichier, nom d'outil, URL, HTML — est une entrée contrôlée par l'utilisateur et mérite le même traitement qu'un paramètre de requête.
RAG : le maillon faible s'appelle souvent la base vectorielle
LLM08 est l'entrée qui surprend le plus les équipes. Une base vectorielle contenant les embeddings de tout votre Confluence, de votre CRM et du drive RH est de fait une copie secondaire de vos données — sans aucune des ACL d'origine. Deux modes de défaillance dominent.
D'abord le post-filtrage : récupérer le top-k puis écarter les chunks que l'utilisateur n'a pas le droit de voir fuit par les signaux de pertinence et renvoie un contexte pauvre et incohérent. Les filtres doivent s'appliquer au moment de la requête, à partir de l'identité de l'appelant et de métadonnées écrites à l'ingestion. Ensuite les ACL périmées : les droits changent dans le système source, personne ne réindexe, et un document reste lisible dans le RAG longtemps après avoir été restreint. Construisez le chemin de réindexation avant de construire le chatbot.
MLSecOps : transformer le Top 10 en pipelines
Le MLSecOps consiste simplement à reconnaître qu'un modèle est un artefact de build, avec une chaîne d'approvisionnement, une porte de déploiement et une posture runtime — comme une image de conteneur, à ceci près qu'il est opaque, stochastique et souvent téléchargé depuis Internet. Quatre plans à couvrir.
Chaîne d'approvisionnement. Les poids sont exécutables : un checkpoint PyTorch historique est un pickle, et le charger exécute du code arbitraire. Imposez safetensors, scannez les artefacts avec un model scanner, épinglez les révisions Hugging Face par SHA de commit et non par branche, et miroitez tout dans un registre interne — des artefacts OCI dans Harbor ou Artifactory fonctionnent très bien et vous font hériter de l'outillage de provenance déjà en place pour les images. Signez avec Sigstore/cosign et publiez un ML-BOM (CycloneDX gère les composants de machine learning) à côté du SBOM.
Build et CI. Les évaluations de sécurité appartiennent au pipeline, pas au pentest annuel. Des outils de red teaming automatisé comme garak, PyRIT (Microsoft) ou promptfoo s'exécutent en job et font échouer le build lorsque la résistance au jailbreak ou à la fuite régresse par rapport à une baseline. Les résultats sont des artefacts de test comme les autres.
name: llm-security-gate
on: [pull_request]
jobs:
redteam:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install garak promptfoo
# Sondes injection, fuite de contexte, encodages exotiques
- run: garak --model_type rest --generator_option_file gen.json \
--probes promptinject,leakreplay,encoding \
--report_prefix artifacts/garak
# Evals sur golden set avec seuil bloquant
- run: promptfoo eval -c promptfooconfig.yaml --fail-on-error
- uses: actions/upload-artifact@v4
with: { name: llm-security, path: artifacts/ }Déploiement. L'admission control que vous appliquez aux images vaut pour les modèles. Une policy Kyverno ou OPA peut refuser toute charge d'inférence dont l'artefact n'est pas signé, provient d'un registre externe ou ne porte pas de label de niveau de risque. Associez-y une NetworkPolicy en default-deny et une allowlist d'egress : à elle seule, cette mesure transforme la plupart des injections réussies en échec journalisé plutôt qu'en fuite de données.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-models
spec:
validationFailureAction: Enforce
rules:
- name: verify-model-artifact
match:
any:
- resources:
kinds: [Pod]
namespaces: [ml-serving]
verifyImages:
- imageReferences:
- "registry.interne/models/*"
attestors:
- entries:
- keyless:
issuer: https://token.actions.githubusercontent.com
subject: https://github.com/acme/model-registry/*Runtime. Empilez les garde-fous des deux côtés du modèle : classifieur en entrée, classifieur en sortie (Llama Guard, NeMo Guardrails ou équivalent managé), rédaction des données personnelles avant que la requête ne quitte votre périmètre, détection de secrets dans les deux sens. Instrumentez avec les conventions sémantiques GenAI d'OpenTelemetry pour que prompts, appels d'outils, comptes de tokens et latences atterrissent dans les mêmes traces que le reste de la plateforme. Puis câblez des budgets de tokens par tenant et des limites dures d'étapes par run d'agent : LLM10 est le point de convergence entre sécurité et FinOps, et c'est le contrôle le plus souvent absent.
Gouvernance : l'inventaire d'abord
NIST AI RMF, ISO/IEC 42001 et le règlement européen sur l'IA poussent tous dans la même direction : être capable d'énumérer ses systèmes d'IA, leur finalité, leurs données et leur niveau de risque. En pratique, le blocage vient rarement du référentiel — il vient du shadow AI. On ne certifie pas ce qu'on ne voit pas, et une part notable des usages GenAI en grande entreprise passe encore par des clés d'API non gérées et des comptes personnels. Une politique d'egress plus une passerelle par laquelle tout appel modèle doit transiter valent mieux que trois mois de rédaction de politique.
Une feuille de route 90 jours
Si vous partez de zéro, la séquence qui réduit le plus de risque par sprint est la suivante : (1) constituer l'inventaire des cas d'usage GenAI et router tout le trafic par une passerelle unique ; (2) classer chaque cas d'usage par rayon d'explosion, pas par effet de mode, et ramener les privilèges des agents au minimum ; (3) poser les contrôles de supply chain — safetensors, scan, registre interne, vérification de signature à l'admission ; (4) intégrer red teaming automatisé et evals sur golden set dans la CI avec une porte bloquante ; (5) boucler avec le tracing, les budgets de tokens et un playbook d'incident qui traite une injection réussie comme n'importe quelle compromission de credentials.
Rien de tout cela n'exige d'outillage exotique. La vérité inconfortable du MLSecOps, c'est qu'il s'agit à 80 % du DevSecOps que vous maîtrisez déjà, appliqué à une classe d'artefacts que votre équipe plateforme n'a pas encore onboardée — plus une primitive réellement nouvelle : ne jamais accorder à la sortie d'un modèle une autorité qu'elle ne devrait pas avoir.
