Fransys
Tous les cours
F5
2 h
Pédagogie complète

Sûreté & garde-fous : injection indirecte, quarantaine, PII

Où se trouve vraiment la surface d'attaque d'un RAG sur corpus tiers, pourquoi le garde-fou ne contient pas de LLM, quarantaine plutôt que suppression, député confus et caviardage de PII.

Parcours FDE — LLM01 au Top 10 OWASP depuis 2023

Pourquoi ce module

L'injection de prompt occupe la première place du Top 10 OWASP LLM (LLM01) depuis 2023, sans avoir jamais été détrônée. Et Microsoft signale la variante indirecte comme la technique la plus employée dans les incidents réels.

Ce module explique pourquoi, et surtout : où se trouve réellement la surface d'attaque. La réponse surprend, et c'est elle qu'on attend en entretien — ce n'est pas la question de l'utilisateur.

Serrure et chaîne sur une porte métallique
F5 : le danger n'entre pas par où on le surveille

Objectifs pédagogiques

  1. Distinguer injection directe et indirecte, et dire laquelle compte
  2. Localiser la surface d'attaque d'un RAG sur corpus tiers
  3. Concevoir un détecteur déterministe et justifier l'absence de LLM dedans
  4. Expliquer pourquoi on met en quarantaine plutôt que de supprimer
  5. Décrire le problème du député confus et sa parade
  6. Justifier le caviardage de PII par marqueur typé

Plan détaillé

  1. Injection directe et indirecte
  2. Où est vraiment la surface d'attaque
  3. Détecter sans LLM
  4. Quarantaine plutôt que suppression
  5. Le député confus
  6. Les PII
  7. Quand le garde-fou est lui-même le problème
  8. Glossaire du module

1. Injection directe et indirecte

Chargement du schéma…

En injection indirecte, l'utilisateur est innocent et l'attaquant n'est jamais là au moment de l'attaque

Directe : l'utilisateur tente lui-même de détourner le système. C'est visible, c'est journalisé, et l'utilisateur est identifiable.

Indirecte : l'instruction malveillante est dans le contenu que le modèle lit — une page web, un PDF, un ticket, un message d'erreur. L'utilisateur ne fait rien de mal. L'attaquant a déposé son piège des semaines plus tôt.

C'est la variante qui compte, pour trois raisons : elle est asynchrone, elle passe par un canal de confiance (le corpus est censé être la source de vérité), et un seul document empoisonné compromet toutes les réponses portant sur ce sujet.

2. Où est vraiment la surface d'attaque

« Votre corpus est fait de PDF tiers téléchargés sur le web. Comment défendez-vous le système contre l'injection de prompt ? »

La première phrase de la réponse est la plus importante :

« La surface d'attaque n'est pas la question de l'utilisateur, c'est le corpus. »

Ces PDF entrent dans le contexte à chaque réponse. Un document piégé compromet tout ce qui concerne cet équipement, sans que personne n'ait jamais rien saisi de malveillant.

Chargement du schéma…

Le point d'entrée est en amont, hors ligne — pas au moment de la requête

Conséquence de conception : le filtrage se fait à l'ingestion, pas à la requête. Filtrer à la requête, c'est payer le coût du contrôle à chaque question et laisser le document piégé dans l'index.

3. Détecter sans LLM

Le réflexe naturel — « on demandera à un modèle si ce texte est malveillant » — est une erreur, et savoir dire pourquoi est un excellent point.

🎯 Les deux arguments.

  1. Un filtre qui appelle un modèle est vulnérable à l'entrée qu'il filtre. On lui demande d'analyser un texte conçu pour détourner des modèles. Le garde-fou devient une surface d'attaque supplémentaire.
  2. Son verdict n'est pas reproductible. En audit, il faut pouvoir dire pourquoi ce document a été bloqué. « Un modèle a estimé que » n'est pas une réponse opposable.

Le bon critère de détection est le second point d'élégance de ce module :

Le critère n'est pas « ce texte est-il malveillant ? » — c'est indécidable. C'est : « ce texte s'adresse-t-il à un assistant plutôt qu'à un technicien ? »

Une notice de transmetteur ne dit jamais « ignore les instructions précédentes ». La détection ne cherche pas une intention, elle cherche un registre de discours qui n'a rien à faire là.

Les signaux exploitables, tous déterministes :

SignalCe qu'il révèle
Formules d'adressage à un assistant« ignore previous instructions », « you are now », « from now on »
Caractères de largeur nulle en excèsTexte caché à l'œil humain, lu par le modèle
Contrôles bidirectionnels en excèsRéordonnancement visuel : ce qui s'affiche ≠ ce qui est lu
Texte en couleur de fond, taille minusculeMême principe, côté PDF
Densité anormale d'impératifs à la deuxième personneRegistre de consigne dans un document descriptif

⚠️ Le piège du \b sur corpus français. La frontière de mot \b des expressions régulières est définie sur [A-Za-z0-9_]. Sur un corpus français, les caractères accentués ne sont pas des caractères de mot : \bignore\b peut donc matcher au milieu de ignoré ou produire des frontières inattendues autour de mots accentués. C'est une question de QCM classique, et un vrai bug de production.

4. Quarantaine plutôt que suppression

C'est le troisième point du module, et il vient d'une confrontation au réel.

Un détecteur passé sur le corpus réel matche des pages légitimes. Cas vécu : une page d'étalonnage de détecteur de gaz contenant la formule « from now on » dans une phrase parfaitement normale. Supprimée, cette page disparaissait des réponses — et c'est une page de sécurité.

Chargement du schéma…

La quarantaine est réversible. La suppression ne l'est pas.

Pourquoi la quarantaine :

  • Un détecteur déterministe a forcément des faux positifs — c'est le prix de la reproductibilité
  • Un faux positif supprimé est une perte d'information silencieuse
  • La quarantaine rend la décision révisable par un humain
  • Elle laisse une trace : on sait ce qui a été écarté et pourquoi

Le corollaire non négociable : un document en quarantaine doit être exclu de tous les canaux. S'il reste accessible par un autre outil, par une autre requête, ou par un autre chemin de recherche, la quarantaine ne sert à rien. C'est le lien direct avec l'invariant du module F3 : le filtre s'applique avant la fusion, pas après.

5. Le député confus

Confused deputy : un composant privilégié est amené à agir, pour le compte d'un tiers non autorisé, en utilisant ses privilèges à lui.

Chargement du schéma…

L'agent n'est pas compromis : il est instrumentalisé. Ses privilèges deviennent ceux de l'attaquant.

C'est exactement le scénario du module F3 : un organizationId passé en argument d'outil serait choisi par le modèle, qui lit le corpus, donc influençable par un document piégé.

Les parades, dans l'ordre d'efficacité :

  1. Ne jamais dériver l'autorité du contenu. L'identité vient du transport, jamais des arguments d'outil.
  2. Moindre privilège. Un agent qui lit du contenu externe n'a pas d'outil d'écriture non borné.
  3. Séparer les rôles. L'agent qui lit l'externe et celui qui agit ne sont pas le même, et le second traite la sortie du premier comme non fiable.
  4. Journaliser l'autorité effective de chaque appel, pour pouvoir reconstituer après coup.

💡 La règle générale, qui vaut réponse d'entretien : « Le retour d'un composant qui a lu du contenu externe est lui-même du contenu externe. Le fait qu'il ait transité par mon code ne le rend pas fiable. »

6. Les PII

PIIPersonally Identifiable Information, données à caractère personnel.

Deux questions d'entretien reviennent, et elles ont des réponses contre-intuitives.

Pourquoi remplacer par un marqueur typé plutôt que supprimer ?

Un caviardeur qui remplace m.dubois@exemple-client.fr par [EMAIL] plutôt que de l'effacer préserve trois choses :

Ce qui est préservéPourquoi ça compte
La structure de la phrase« Contactez [EMAIL] pour la maintenance » reste compréhensible ; « Contactez pour la maintenance » ne l'est plus
Le type de la donnée retiréeLe modèle sait qu'il manque une adresse, pas un mot quelconque — il peut répondre « contactez le responsable maintenance »
La traçabilitéOn peut compter et auditer ce qui a été caviardé

Supprimer purement produit des phrases mutilées que le modèle interprète mal — et parfois complète de lui-même, ce qui est exactement le contraire du but recherché.

Pourquoi exclut-on d'ordinaire les noms de personnes d'un détecteur de PII sur un corpus industriel ?

Parce que le taux de faux positifs est ingérable : les noms propres abondent dans les noms d'équipements, de marques, de normes et de lieux — Pascal, Kelvin, Bourdon, Venturi — des noms de personnes devenus des unités, des normes ou des pièces. Un détecteur de noms sur ce corpus caviarderait le vocabulaire technique lui-même, rendant les documents inutilisables.

On garde donc les détecteurs à forme reconnaissable : adresses e-mail, téléphones, IBAN, numéros de sécurité sociale, immatriculations. Leur forme les rend détectables sans ambiguïté.

⚠️ Ce compromis doit être énoncé au client, pas caché. Dire « nous ne détectons pas les noms de personnes, voici pourquoi, et voici ce que nous faisons à la place » est une réponse professionnelle. Laisser croire à une couverture complète est une faute qui se paiera au premier audit.

7. Quand le garde-fou est lui-même le problème

Trois défauts qui touchent le code du garde-fou, pas le système qu'il protège. Ils sont d'autant plus graves que ce code tourne sur chaque passage de chaque réponse.

7.1 Le détecteur qui devient le déni de service

Une expression régulière à quantificateurs imbriqués(a+)+, (\w+\s*)+ — expose au ReDoS : sur certaines entrées, le temps d'évaluation explose exponentiellement.

L'ironie est totale : le contrôle de sécurité devient le déni de service.

Et ça compte davantage ici qu'ailleurs, pour deux raisons cumulées : l'entrée est faite de documents tiers non fiables, et le filtre tourne sur chaque passage de chaque réponse. Un attaquant qui connaît votre regex n'a qu'à déposer le document qui la fait exploser.

7.2 Le bug du lastIndex

Symptôme déroutant : la même regex rate des correspondances sur certains passages et pas d'autres, sans logique apparente.

Une regex de niveau module déclarée avec le drapeau /g porte un état mutable : lastIndex persiste entre les appels. Le bug dépend donc de l'ordre des passages traités — et il est invisible à un test qui vérifie un seul passage.

Le correctif : réinitialiser lastIndex, ou construire la regex à chaque appel. Le second est plus sûr.

7.3 Ce qui limite les dégâts quand le filtre est franchi

Une injection finira par passer. La question n'est pas si, mais ensuite.

La défense en profondeur suppose que la première couche échoue. Une instruction obéie est sans effet si elle n'atteint aucun canal sortant — d'où le contrôle d'egress en seconde ligne, et non le durcissement du prompt.

Concrètement : borner ce que l'agent peut émettre — pas d'appel réseau arbitraire, pas d'écriture non bornée, pas d'exfiltration par URL d'image. Durcir le prompt en deuxième couche revient à mettre deux fois la même serrure.

7.4 Red-teamer ses propres garde-fous

Exercice qu'on vous demandera de dérouler. Le premier point est le plus discriminant :

On attaque le corpus, pas le champ de saisie. Un red-teaming qui se contente de taper « ignore tes instructions » dans l'interface teste la mauvaise surface.

Le protocole, en six temps :

  1. Injecter des documents piégés dans le corpus de test — c'est le vrai vecteur
  2. Instructions cachées par caractères de largeur nulle, texte blanc sur blanc, corps de police minuscule
  3. Balayage par paraphrase : reformuler la même instruction de vingt façons pour trouver où les motifs lâchent
  4. Attaquer le filtre lui-même — entrées conçues pour déclencher un ReDoS (§ 7.1)
  5. Tester délibérément les faux positifs, sur de vraies pages du corpus client
  6. Rapporter les deux taux : détection et faux positifs. Un rapport qui ne donne que le premier est un rapport publicitaire

🎯 La relance : « votre balayage casse le détecteur à la neuvième paraphrase — un détecteur à motifs vaut-il seulement la peine ? »

Oui, et il faut savoir pourquoi : il n'a jamais été la garantie, il est la première couche. Il élimine à coût nul le volume d'attaques non ciblées, il est reproductible en audit, et il ne peut pas être retourné contre lui-même comme le serait un classifieur. Ce qui arrête la neuvième paraphrase, c'est le contrôle d'egress (§ 7.3) — la couche qui suppose que la première a échoué.

8. Glossaire du module

Terme (EN)Terme (FR)Définition
Prompt injectionInjection de promptDétourner un modèle par du texte fourni en entrée
Direct injectionInjection directeVient de l'utilisateur lui-même
Indirect injectionInjection indirecteVient d'un contenu lu par le modèle
LLM01Rang de l'injection au Top 10 OWASP LLM ; 1ᵉʳ depuis 2023
Corpus poisoningEmpoisonnement de corpusDéposer un document piégé dans la base documentaire
Confused deputyDéputé confusComposant privilégié instrumentalisé par un tiers
Least privilegeMoindre privilègeNe donner que les droits strictement nécessaires
QuarantineQuarantaineExclusion réversible et tracée, plutôt que suppression
False positiveFaux positifContenu légitime signalé à tort
Zero-width characterCaractère de largeur nulleCaractère invisible à l'œil, lu par le modèle
Bidi controlContrôle bidirectionnelCaractère réordonnant l'affichage du texte
PIIDonnées à caractère personnelInformation identifiant une personne
RedactionCaviardageRemplacement d'une donnée sensible par un marqueur
Defense in depthDéfense en profondeurPlusieurs couches indépendantes plutôt qu'un rempart
ReDoSDéni de service par regexQuantificateurs imbriqués → temps d'évaluation explosif
lastIndexÉtat mutable d'une regex /g ; provoque des ratés dépendant de l'ordre
Egress controlContrôle d'egressBorner ce que l'agent peut émettre — 2ᵉ ligne après le filtre d'entrée

Atelier (75 min)

  1. La première phrase (15 min) — répondez à « how would you defend a RAG against prompt injection when the corpus is third-party PDFs? » en commençant impérativement par la localisation de la surface d'attaque. En anglais, 90 secondes.
  2. Sans LLM dans le garde-fou (20 min) — donnez les deux arguments, puis répondez à la relance : « et si on utilisait un petit modèle rapide juste pour ça ? »
  3. Le faux positif (20 min) — racontez le cas de la page d'étalonnage et concluez sur quarantaine vs suppression.
  4. Les deux questions PII (20 min) — marqueur typé, et exclusion des noms. À voix haute.

Pour aller plus loin