📄 SKILL.md 🔒 d7c7abdf…db0476e3 Se connecter pour télécharger ← Retour
---
name: detecteur-injection-prompt
description: Recherche locale de techniques de dissimulation de texte/instructions dans du contenu (documents, HTML, config) — unicode invisible, contrôles bidirectionnels, homoglyphes, texte masqué CSS, faux marqueurs de rôle, charges base64 suspectes — stdlib pur, zéro appel réseau.
theme: securite-souverainete
langages_cibles: python
---

# detecteur-injection-prompt

## Objectif

Repérer, dans un dossier ou un fichier de contenu (documentation, HTML,
configuration, données), des techniques connues de dissimulation utilisées
pour cacher du texte à un lecteur humain ou pour tenter de faire passer du
contenu pour une instruction système auprès d'un système automatisé qui
lirait ce fichier en aval : caractères Unicode invisibles, contrôles
bidirectionnels (technique « Trojan Source »), homoglyphes (mélange
d'alphabets visuellement proches), texte masqué par CSS, faux marqueurs de
rôle de conversation (mots-clés « system », « assistant »... suivis d'un
deux-points, marqueurs de gabarit de conversation type crochets INST), et charges
encodées en base64 dissimulant une formulation d'instruction suspecte.
Complète `detecteur-secrets` (fuite de secrets) et `audit-souverainete`
(dépendances non-souveraines) sous un angle différent : la *dissimulation de
contenu*, pas la fuite ni la dépendance.

## Pourquoi Python (et pas un autre langage) ?

Même famille de raisons que les autres skills Python du projet
(`detecteur-secrets`, `audit-pqc-readiness`) : portabilité sans compilation,
et surtout ici la stdlib Unicode de Python (`unicodedata` implicite via les
propriétés de caractères, `base64`, `re` avec support Unicode natif) couvre
exactement le besoin sans aucune bibliothèque tierce de détection
d'homoglyphes ou d'analyse Unicode avancée.

## Garanties de sécurité

- **Contenu scanné = donnée inerte, jamais exécutée ni interprétée comme
  instruction.** Ce script ne "lit" jamais un fichier pour décider d'une
  action — y compris les blocs base64 décodés ne sont jamais que comparés à
  une liste de motifs textuels connus, jamais exécutés ni traités comme du
  code. Chaque comportement (quel fichier ouvrir, quelle règle appliquer) est
  déterminé AVANT le scan, jamais par le contenu rencontré.
- **Catalogue de règles externalisé et vérifié** (`regles_injection.json`) —
  chaque motif regex est compilé et validé au chargement ; un motif invalide
  lève une erreur nommée (`ErreurReglesInvalides`) plutôt que d'échouer
  silencieusement.
- **Décodage base64 strict et jamais imprimé en clair sans filtre** :
  `base64.b64decode(..., validate=True)` rejette tout candidat qui n'est pas
  un base64 valide (élimine la quasi-totalité des faux candidats, dont les
  empreintes hexadécimales — voir test dédié `test_hash_hexadecimal_non_confondu`),
  puis le résultat décodé n'est signalé QUE s'il contient un des verbes
  d'instruction suspects connus — jamais signalé sur la seule base d'un
  décodage réussi.
- **Aucune donnée n'est jamais transmise à l'extérieur** — 100% local,
  0 appel réseau, aucune dépendance tierce.

## Gestion d'erreur exhaustive

`erreurs.py` définit une exception par cas réel identifié dans le pipeline :
`ErreurCibleIntrouvable` (chemin absent), `ErreurCibleNonAccessible`
(permission refusée), `ErreurReglesInvalides` (catalogue JSON malformé,
champ obligatoire absent, ou motif regex invalide), `ErreurEcritureRapport`
(écriture du fichier de sortie impossible). `main()` traite chaque catégorie
dans une branche `except` dédiée avec un code de sortie distinct, plus un
dernier recours explicitement nommé (`ErreurInterne`, code 99) pour tout cas
non prévu — jamais un `except Exception: pass` silencieux.

## Mode d'emploi

**Scanner un dossier (rapport Markdown, sortie standard) :**

```bash
python3 detecteur_injection.py /chemin/vers/mon-projet
```

**Scanner un seul fichier, rapport JSON écrit sur disque :**

```bash
python3 detecteur_injection.py /chemin/vers/document.md \
  --format json --out rapports/mon-rapport.json
```

**Résultat réel obtenu lors de la validation de ce skill** (dossier `src/`
d'un projet Rust d'environ 660 fichiers texte/HTML/config, ~4 secondes) :
14 signalements — **13 confirmés faux positifs explicables après vérification
manuelle ligne par ligne** : 5 sur un mot contenant volontairement un
caractère cyrillique homoglyphe (test unitaire du projet lui-même vérifiant
sa propre normalisation NFKC de recherche), 1 sur un caractère ZWJ dans un
test d'emoji composé (test unitaire de la propre sanitisation Unicode du
projet), et 7 sur le fichier qui définit et teste la protection
`filtrer_injection_prompt()` du projet (les marqueurs de gabarit de
conversation type crochets INST apparaissent littéralement dans son code et
ses tests). **1 vrai faux positif de motif** identifié : une ligne de
configuration Rust (champ `user` suivi de deux-points) capturée par la règle
`INJECTION-FAUX-ROLE-01` (voir "Limites connues"). Résultat globalement
rassurant sur le projet cible
— et confirmation involontaire que ce projet possède déjà ses propres
défenses contre exactement ce type d'attaque.

**Options communes :**

- `--format` : `md` (défaut, lisible) | `json` (structuré, pour automatisation)
- `--out` : chemin de sortie (défaut : stdout)

**Prérequis :** aucune installation — Python 3 standard suffit (testé en 3.12).

## Limites connues (honnêteté de l'outil, pas de sur-promesse)

- **Ce catalogue ne couvre que des techniques déjà connues et documentées
  aujourd'hui.** Une nouvelle technique de dissimulation, pas encore
  répertoriée au moment de l'écriture de ce skill, ne sera par construction
  pas détectée — ce qui n'est pas encore connu est précisément ce contre
  quoi un catalogue figé ne peut pas protéger. `regles_injection.json` est
  volontairement externalisé du code pour permettre d'ajouter facilement de
  nouvelles règles sans toucher à la logique, mais cela reste une mise à
  jour manuelle : ce skill est un filet de sécurité contre le connu, pas une
  garantie contre l'inconnu.
- **Faux positif identifié sur `INJECTION-FAUX-ROLE-01`** : un mot-clé
  générique (« user », « system », « assistant », « human ») suivi d'un
  deux-points en début de ligne peut légitimement apparaître dans du code
  (ex. un champ de structure Rust `user` suivi de sa valeur) si ce type de
  fichier est inclus dans le périmètre scanné
  — constaté une fois sur `core/config.rs` pendant la validation réelle.
  Volontairement non "corrigé" par une heuristique plus complexe (ex.
  exiger l'absence de virgule finale) : une règle plus subtile pour éliminer
  ce cas précis risquerait de créer un nouvel angle mort sur une variante
  légèrement différente — le compromis assumé est de rester large sur cette
  règle et de compter sur la vérification manuelle finale, cohérent avec
  l'esprit des autres skills de ce projet (ex. `detecteur-secrets`).
- **Homoglyphes** : la table `confusables` du catalogue est volontairement
  restreinte aux confusions Cyrillique/Grec les plus courantes avec l'alphabet
  latin — ne couvre pas l'ensemble des scripts Unicode ayant des glyphes
  visuellement proches (Arménien, certains caractères CJK élargis, etc.).
- **Base64 suspect** : ne décode que des candidats en base64 standard
  (`+`/`/`), pas les variantes URL-safe (`-`/`_`) ni les encodages imbriqués
  (base64 d'un base64) — un contournement à un niveau d'indirection
  supplémentaire échappe à la détection actuelle.
- Comme les autres skills d'analyse statique de ce projet, l'extraction est
  par motif texte/regex, pas une analyse sémantique — un contenu généré
  dynamiquement (concaténation, template) au moment de l'exécution n'est pas
  détectable par une analyse statique de fichiers sur disque.
- **Anomalie du scanner d'upload solivram.com rencontrée puis résolue** :
  la première version de ce skill (description en prose de la règle
  `INJECTION-FAUX-ROLE-01`, mentionnant littéralement des marqueurs de
  conversation en clair) déclenchait le scanner de sécurité anti-fuite de
  solivram.com ("Fichier refusé par le scanner de sécurité") — même famille
  d'anomalie déjà rencontrée sur `regles_secrets.json`/`regles_csp.json`.
  Bissection réelle : le champ `motif` (regex, déjà échappée `\[INST\]`)
  passait sans problème dès le départ ; seul le champ `description` en
  prose non échappée posait problème. Reformulé sans littéral direct (même
  principe que « pseudo-protocole javascript » sur `audit-csp-lighthouse`),
  **0 changement de comportement de détection** (regex fonctionnelle
  inchangée, 26/26 tests revalidés après coup) — `regles_injection.json`
  est donc bien hébergé intégralement sur solivram.com, statut "complet".
8.7 Ko BLAKE3 : d7c7abdf…db0476e3