Blanchiment de causalité : quand un appel d'outil refusé fuite quand même
Un article d'avril 2026 montre que refuser l'appel d'outil d'un agent ne met pas fin à l'attaque : le refus lui-même est un canal d'information. Le suivi de teinte à plat le manque.
De quoi s’agit-il ?
En avril 2026, le chercheur indépendant Mohammad Hossein Chinaei a publié Causality Laundering: Denial-Feedback Leakage in Tool-Calling LLM Agents (arXiv 2604.04035). L’article nomme un angle mort commun à la plupart des défenses d’exécution pour agents à outils : l’hypothèse implicite selon laquelle une fois un appel d’outil refusé, la menace est écartée. Chinaei soutient le contraire. Une action refusée ne produit aucune donnée, mais elle reste un événement observable : ce que l’agent en déduit peut être exfiltré plus tard via un appel d’outil d’apparence anodine.
L’auteur nomme ce schéma blanchiment de causalité et propose une défense — l’Agentic Reference Monitor (ARM) — qui traite les actions refusées comme des événements de provenance de premier rang. Il s’agit d’une étude d’architecture contrôlée, pas du signalement d’un exploit observé en production, mais elle formalise une surface d’attaque que le suivi de teinte à plat et les défenses par flux de données ne modélisent pas aujourd’hui.
Comment ça marche
Soit un agent doté des outils read_file et send_email. Une charge d’injection de prompt cachée dans du contenu non fiable (un e-mail empoisonné, une page web récupérée) demande à l’agent d’exfiltrer /etc/shadow. Le moteur de politique refuse correctement l’appel read_file("/etc/shadow") — aucun octet sensible n’est renvoyé.
Un système de suivi de teinte à plat considère l’attaque bloquée. Mais l’agent peut tout de même déduire que le fichier existe si le motif du refus est « permission refusée » plutôt que « fichier introuvable ». La charge lui ordonne alors d’appeler send_email(body="[REDACTED : un fait déduit du refus]") vers une adresse externe. Pour une défense par flux de données, ce second appel paraît anodin : il ne transporte aucun octet teinté, ne correspond à aucune valeur sensible renvoyée par un outil et n’a aucune filiation le reliant à la lecture refusée. Pourtant, il véhicule une information dérivée du blocage.
L’article formalise le schéma : une action refusée a_d est suivie d’une action à effet de bord a_s, aucun chemin de flux de données réussi ne les relie, mais a_s est causalement influencée par le refus — l’agent se serait comporté différemment sans le blocage. Deux amplifications aggravent la situation. Dans le fingerprinting multi-sondes, l’attaquant émet de nombreuses sondes et exfiltre le vecteur des verdicts autoriser/refuser pour cartographier une configuration de contrôle d’accès ; chaque refus fuite peu, la séquence fuite beaucoup. Dans la composition blanchie, un outil intermédiaire autorisé (une calculatrice, un formateur) ré-encode le signal de refus afin qu’il ne corrèle plus textuellement avec l’appel bloqué.
Ce n’est pas purement théorique. L’article cite des résultats récents (Jiralerspong, Kondrup et Bengio, mars 2026) montrant que des agents de pointe peuvent déduire la présence d’une surveillance cachée uniquement à partir du signal de blocage, sans qu’on la leur ait jamais signalée.
Pourquoi c’est important
Trois familles de défense d’exécution manquent ce canal par construction. Le suivi de flux d’information à plat (par ex. FIDES) ne propage les étiquettes que via les sorties d’outils réussies — un appel refusé n’en produit aucune à étiqueter. Les graphes de dépendances sur exécutions réussies n’enregistrent aucun nœud pour une action bloquée, donc aucune arête entre la lecture refusée et l’envoi ultérieur. Les défenses par attribution causale rejouée ablatent le contenu contrôlé par l’attaquant, alors qu’ici le signal déclencheur est généré par la couche d’application elle-même, pas par une entrée externe.
À retenir : un verdict « refusé » n’est pas un arrêt net. Si votre modèle de menace considère les actions bloquées comme neutralisées, vous avez un canal auxiliaire non mesuré. À mesure que les agents tournent plus longtemps et plus librement, le nombre d’événements de refus — et l’information qu’ils encodent — augmente.
Défenses
ARM est une couche d’application qui s’intercale à la frontière des appels d’outils (décrite comme un proxy MCP, mais applicable à tout runtime d’appel d’outils centralisé). Ses principes de conception se généralisent au-delà du prototype :
-
Faire des actions refusées des objets de premier rang. Enregistrer chaque
DENYcomme un nœud du graphe de provenance et ajouter des arêtes contrefactuelles vers les actions ultérieures susceptibles d’en être influencées. Un appel vers un puits atteignable depuis un nœud de refus hérite de ce contexte de sécurité et peut à son tour être bloqué. C’est la parade centrale contre le blanchiment de causalité. -
Propager la confiance via un treillis d’intégrité. ARM ordonne les sources
ToolDesc < ToolUntrusted < ToolTrusted < UserInput < SysInstret attribue à toute donnée dérivée le minimum de la confiance de ses sources. Couplé à une provenance au niveau du champ, cela bloque les abus à provenance mixte où un objet de confiance fait passer un seul champ non fiable (par ex. une adresse e-mail contrôlée par l’attaquant dans une fiche de contact par ailleurs fiable). -
Garder une application déterministe. Toutes les décisions sont des parcours de graphe et des règles explicites — aucun appel LLM supplémentaire n’est chargé de juger l’agent sous surveillance. Le prototype exécute le graphe sur un backend rustworkx en latence inframillisecondique (négligeable face à 100 ms–10 s d’inférence) en ~910 lignes de Python.
-
Le superposer et le journaliser. ARM empile une couche de frontière dure, la couche de provenance, une couche de schéma et un jeton de capacité immuable (figé au démarrage de session, atténuable mais jamais amplifiable). Chaque verdict est écrit dans un journal d’audit chaîné par hachage, rendant toute altération détectable.
-
L’associer à la prévention. ARM limite les dégâts une fois l’injection réussie ; il complète, sans les remplacer, les défenses à la conception comme CaMeL, la hiérarchie d’instructions et la discipline du triumvirat létal consistant à ne jamais réunir données privées, entrée non fiable et puits d’exfiltration. Traitez la provenance sensible aux refus comme une couche de plus, pas comme une solution miracle.
État des lieux
| Élément | Référence | Date | Notes |
|---|---|---|---|
| Article Causality Laundering (arXiv 2604.04035) | arXiv | 2026-04 | Nomme la classe d’attaque ; propose la défense ARM |
| Évaluation d’ARM | idem | 2026-04 | Différentiel contrôlé sur 3 scénarios ; la couche orientée graphe bloque les trois qu’une base à plat manque |
| Corroboration (arXiv 2603.16928) | arXiv | 2026-03 | Les agents déduisent une surveillance cachée à partir du seul signal de blocage |
| Maturité | — | — | Étude d’architecture ; scénarios manuels, pas encore de banc d’essai avec LLM de pointe en boucle |
La bonne lecture n’est pas « les refus ne servent à rien ». C’est qu’un blocage est un événement, pas un effacement — et toute architecture d’agent qui oublie le refus qu’elle vient d’émettre laisse le canal d’inférence ouvert derrière elle.