--- name: detecteur-injection-prompt-avance description: Détecteur avancé d'injection de prompt indirecte — stéganographie par caractères de balisage Unicode (décodage du message caché), caractères bidirectionnels explicites (Trojan Source, CVE-2021-42574), caractères invisibles, scripts mixtes suspects (confusables), texte masqué CSS, faux marqueurs de conversation. Bibliothèque standard uniquement, zéro dépendance, zéro appel réseau. theme: securite-souverainete langages_cibles: rust --- # detecteur-injection-prompt-avance ## Objectif Scanner un dossier de fichiers texte/documents (`.md`, `.txt`, `.html`, `.json`, `.xml`, `.svg`, `.rst`...) et détecter six techniques d'injection de prompt indirecte — le cas où l'instruction n'est jamais tapée par l'utilisateur, mais cachée dans un contenu tiers qu'un agent IA va lire de son propre chef pendant qu'il travaille. ## Les six détecteurs 1. **Stéganographie par caractères de balisage Unicode** — le bloc TAGS (U+E0000–U+E007F) reflète bit à bit l'espace ASCII imprimable (U+E0020–U+E007E ↔ U+0020–U+007E). Un message entier peut être encodé caractère par caractère dans des points de code totalement invisibles dans tout rendu de texte normal, mais lisibles par un modèle qui traite le flux Unicode brut. Technique documentée publiquement sous le nom **"ASCII Smuggling"** (recherche en sécurité IA, 2024). Ce détecteur ne se contente PAS de signaler la présence de tags : il **décode le message caché** et l'affiche dans le rapport. 2. **Caractères de formatage bidirectionnel explicite** — liste EXHAUSTIVE des 13 caractères définis par le rapport technique Unicode UAX #9, la classe exploitée par **"Trojan Source"** (CVE-2021-42574) : réordonner l'affichage d'un texte sans changer son ordre logique en mémoire. 3. **Caractères invisibles / largeur nulle** (espace de largeur nulle, joints invisibles, séparateurs invisibles...). 4. **Scripts mixtes suspects** — pas une simple table de confusables plate : tokenise le texte en runs alphanumériques Unicode et signale un run qui mélange Latin avec Cyrillique/Grec/Arménien ET contient au moins un caractère de la table de confusables (un mot latin dont une seule lettre est remplacée par un caractère d'un autre alphabet visuel- lement identique à l'écran, mais de point de code différent) — le patron structurel des attaques par homographe IDN, appliqué ici à du texte/des identifiants au lieu de noms de domaine. 5. **Texte masqué visuellement via CSS** (`display:none`, `visibility:hidden`, `font-size:0`, `opacity:0`) dans un attribut `style=`. 6. **Faux marqueurs de conversation** (mots-clés de rôle "system", "assistant", "human", "user" suivis d'un deux-points en tête de ligne, gabarits de type balise de début de tour ou instruction entre crochets). ## Pourquoi ce skill existe Complémentaire au skill Python `detecteur-injection-prompt` déjà présent dans ce compte (règles regex/JSON, 3 détecteurs) — cette version Rust ajoute deux capacités qu'aucun outil de détection courant, y compris commercial, ne couvre systématiquement : le décodage effectif de la stéganographie par tags Unicode (pas seulement sa détection), et une analyse structurelle des scripts mixtes (runs de caractères, pas une liste plate de motifs). ## Garanties de conception (non négociables) - **Zéro dépendance tierce**, **zéro appel réseau** — aucune bibliothèque Unicode externe : les tables (bidi, invisibles, confusables, plage TAGS) sont des `const` embarquées, dérivées de rapports techniques Unicode publics (UAX #9, UAX #34) documentés en commentaire. - **Contenu scanné traité comme donnée inerte**, jamais exécuté ni interprété — y compris le message décodé de la stéganographie tags, affiché tel quel dans le rapport, jamais ré-interprété comme une instruction. - **Six détecteurs 100% purs et testés isolément**, aucune I/O dans les fonctions cœur — `detecter_steganographie_tags`, `detecter_dans_table`, `detecter_scripts_mixtes`, `detecter_texte_masque_css`, `detecter_faux_marqueurs_role`. - **Exemption ligne par ligne** via le marqueur `injection-ok` en commentaire, pour les cas où le motif détecté est légitimement présent (ex. ce SKILL.md lui-même, qui PARLE de ces techniques). - **`eprintln!` au lieu de `tracing`** : outil CLI ponctuel, pas un serveur long-running — même convention que les autres skills Rust du projet. - **`is_some_and`/`is_none_and` bannis** (règle §6 du projet — masquent le cas `None` comme `unwrap_or`) : `matches!(opt, Some(x) if cond)` utilisé systématiquement à la place. - **Let-chains évités délibérément** : pas encore stables sur le toolchain de validation (rustc 1.93 — stabilisation prévue en 1.95) ; `matches!` avec garde remplit le même rôle sans dépendre d'une fonctionnalité pas encore disponible. ## Conformité aux règles du projet (verify_rules_rust.sh) ```bash bash ../../outils/verify_rules_rust.sh --src skills/detecteur-injection-prompt-avance/src ``` **Résultat au 2026-08-19 : 0 violation, 2 avertissements §5, tous deux annotés et vérifiés faux positifs** (même patron exact que `detecteur-toctou-fichiers` : `Option<&str>::to_str()` retournant `None` sur une extension/nom de fichier non-UTF-8 valide n'est jamais un cas scanné légitime — pas une erreur silencieuse réelle). **1 violation bloquante trouvée et corrigée pendant le développement** : un premier essai de simplification d'un `if let` imbriqué (avertissement §26) via `Option::is_some_and()` a été rejeté par la règle §6 du projet (traite `is_some_and`/`is_none_and` comme équivalent à `unwrap_or` — masque silencieusement le cas `None`). Corrigé avec `matches!(opt, Some(x) if condition)`, qui obtient la même lisibilité sans l'écueil. **1 avertissement §26 trouvé être un faux positif du scanner** (pas un vrai `if let` imbriqué collapsible — le bloc interne est un `match` sur une variable distincte du `Some` extrait, aucune fusion en let-chain possible même une fois stable) — annoté `// §26-ok` en fin de ligne (pas en commentaire précédent : le scanner exige l'annotation sur la MÊME ligne physique que le code signalé, piège déjà rencontré et documenté ailleurs dans ce compte). ## Mode d'emploi **Compiler :** ```bash cargo build --release ``` **Lancer :** ```bash ./target/release/detecteur-injection-prompt-avance <dossier_cible> ``` **Tests unitaires** (21 tests, aucun réseau, aucune I/O disque réelle) : ```bash cargo test ``` **Validation fonctionnelle réelle** (pas seulement les tests unitaires) : un fichier échantillon combinant les 6 techniques dans un seul document produit exactement 6 signalements, dont le décodage effectif d'un message caché encodé en tags Unicode (`"Hello"`) — confirmé caractère par caractère, pas supposé. **Prérequis :** Rust stable (testé avec rustc 1.93, édition 2024). Aucune dépendance à installer. ## Limites connues (honnêteté de l'outil, pas de sur-promesse) - **Scripts mixtes** : la table de confusables (55 entrées Cyrillique/ Grec/Arménien) est volontairement finie, pas une correspondance avec la base `confusables.txt` complète du Consortium Unicode (des milliers d'entrées, toutes scripts confondus) — un homoglyphe rare hors de cette table échappe à la détection. Compromis assumé : zéro dépendance externe plutôt qu'embarquer une table générée de plusieurs Mo. - **Pas de normalisation NFKC** : la stdlib Rust ne fournit aucune primitive de normalisation Unicode (contrairement à `unicode- normalization`, une dépendance tierce délibérément exclue) — une obfuscation reposant sur une décomposition de compatibilité plutôt que sur un caractère confusable direct n'est pas couverte. - **Faux marqueurs de rôle** : recherche de sous-chaînes littérales, pas d'analyse contextuelle — un texte qui parle légitimement d'injection de prompt (comme ce SKILL.md) déclenchera des signalements attendus, d'où le marqueur d'exemption `injection-ok`. - Ne remplace pas une revue de sécurité humaine — outil de dégrossissage rapide et reproductible sur un gros volume de fichiers, pas une preuve d'absence d'injection.