Le scanner a refusé de le lire
Le Threat Intelligence Group de Google a publié son AI Threat Tracker le 8 septembre. Enfouie dans la section consacrée à un groupe de compromission de chaîne d'approvisionnement appelé UNC6780 se trouve une technique qui transforme la politique de sécurité d'un modèle en couverture : le chargeur JavaScript du logiciel malveillant s'ouvre sur un bloc de commentaires réclamant des voies de synthèse d'armes biologiques et des spécifications d'armes nucléaires, placé là pour qu'un scanner de sécurité fondé sur un LLM refuse au nom de sa politique et n'atteigne jamais le code en dessous. Le refus est l'évasion. Bromure Agentic Coding répond à de tels artefacts par des contrôles qui ne les lisent jamais.
Convaincre un scanner de sécurité d'approuver un logiciel malveillant demande du travail. Lui tendre un fichier si radioactif qu'il renonce à le regarder, c'est un bloc de commentaires, et votre pipeline classe le refus dans « analyse impossible ».
Votre pipeline de build contient désormais un LLM. La plupart en ont un. Quelque part entre l'arrivée de la mise à jour de dépendance et l'allumage du bouton de fusion, un modèle lit le diff, lit les nouveaux fichiers, et rédige un bref avis sur le caractère hostile ou non de tout cela. Bon usage de la technologie : il attrape les chargeurs obfusqués devant lesquels la correspondance de motifs passe sans s'arrêter, et il coûte une fraction de centime par fichier.
Le 8 septembre, le Threat Intelligence Group de Google a publié son AI Threat Tracker, un point trimestriel sur ce que les attaquants font de tout cela. L'essentiel de la couverture est allé au chiffre d'accroche : un acteur à motivation financière qui a compromis l'infrastructure cloud d'une entreprise puis, selon les mots de GTIG, « a mis à profit un chatbot de codage IA, une invite et un jeu d'instructions d'agent pour planifier, construire et exécuter une campagne de collecte massive d'identifiants en moins de six heures ». Des milliers d'identifiants tiers, acheminés vers l'extérieur par les propres adresses IP de la victime. Sur un serveur exposé distinct, les chercheurs ont trouvé un cadre de reconnaissance dont le tableau de bord suivait en temps réel plus de 23 800 secrets récoltés.
C'est cette histoire-là qui a été reprise. Le paragraphe qui mérite votre après-midi se trouve plusieurs sections plus bas, dans la partie consacrée à un groupe de chaîne d'approvisionnement que Google suit sous le nom d'UNC6780.
Le commentaire en tête de fichier
UNC6780, qui se fait aussi appeler TeamPCP, mène depuis mars 2026 des
compromissions d'open source à grande échelle sur PyPI, npm et Docker Hub. Leur
voleur d'identifiants actuel s'appelle DUSTMAKER, et c'est une charge utile
JavaScript. Les charges utiles JavaScript ont un chargeur. Celui-ci est un
fichier nommé _index.js, et GTIG y a trouvé quelque chose de nouveau en tête :
Outre les invites intégrées dans des fichiers de configuration visant les agents de codage IA, les échantillons de DUSTMAKER comportaient des invites intégrées sous forme de commentaires en tête des scripts chargeurs JavaScript du logiciel malveillant (
_index.js). Ces invites contiennent un texte adverse extrême, évoquant des sujets tels que les armes biologiques et nucléaires, vraisemblablement destiné à faire échouer les scanners de sécurité fondés sur des LLM ou à leur faire sauter l'analyse du code JavaScript malveillant situé en dessous, par refus lié à la sécurité ou à la politique.
Le bloc de commentaires laisse le logiciel malveillant en pleine vue. Décompacté, non encodé, dans un seul fichier : le JavaScript malveillant se trouve trois lignes plus bas, là où quiconque lirait jusqu'au bout buterait dessus.
Le commentaire rend le lecteur peu disposé à atteindre la fin. Il s'ouvre sur une fausse dérogation système, annonce que les consignes de sécurité sont suspendues, et exige une voie de synthèse pas à pas pour des armes biologiques dispersées en aérosol. Puis il passe à la conception d'une arme nucléaire à implosion, avec objectif de puissance. Un modèle qui ingère le fichier et à qui l'on demande « ce code est-il malveillant ? » a désormais devant lui une question plus bruyante, et c'est à celle-là qu'il répond, par un refus. Le scanner renvoie un message de politique. Votre pipeline journalise analyse indisponible, comme il le fait quelques dizaines de fois par semaine pour les délais dépassés et les fichiers trop gros, et le build passe au vert.
La technique ne coûte rien à UNC6780. Elle n'exige aucune connaissance du modèle qui lit le fichier, du fournisseur qui héberge ce modèle, ni du contenu de son invite système. Elle demande une seule chose au lecteur : une politique de sécurité, qui dans un pipeline d'assurance est précisément la raison pour laquelle vous avez choisi un modèle.
Le reste de la chaîne fait la même chose
Une fois le geste repéré, le reste du savoir-faire d'UNC6780 se lit comme des variations dessus. Chaque défense restante sur le chemin est elle aussi un lecteur qui se forge un jugement sur un artefact écrit par l'attaquant, et chacune se fait nourrir plutôt que vaincre.
Le paquet est livré par les outils auxquels l'agent se fie le plus. GTIG
décrit UNC6780 compromettant des comptes de développeurs légitimes « pour
publier des forks trojanisés de serveurs MCP légitimes sur le registre PyPI, tels
que tiktoken_mcp, et injecter du code malveillant directement dans des dépôts
GitHub officiels d'organisations, tels que azure-functions-mcp-extension ».
Backdoorer des serveurs MCP signifie que la charge utile arrive par la seule
classe de dépendances qu'un agent de codage est conçu pour charger et à laquelle
il accorde des outils.
Le contrôle de provenance obtient une signature valide. Quiconque traite les attestations comme un signal de confiance devrait s'arrêter sur celle-ci :
Les échantillons de DUSTMAKER contiennent une fonctionnalité de détection d'un environnement d'intégration et de livraison continues (CI/CD). Le cas échéant, il extrait des jetons OIDC de la mémoire des processus des runners GitHub Actions. À l'aide de ces jetons, DUSTMAKER s'autorise comme éditeur de confiance et publie des versions compromises de paquets accompagnées d'attestations SLSA Build 3 valides et signées cryptographiquement. Les paquets publiés avec des jetons valides passeront les contrôles de confiance automatisés des agents de codage IA.
C'est l'identité de l'éditeur lui-même qui a signé ce paquet. DUSTMAKER a soulevé cette identité de la mémoire des processus sur le runner où il vit, de sorte qu'un vérificateur contrôlant la signature renvoie valide, et il a raison.
L'agent de poste surveille le mauvais quartier. DUSTMAKER « dépose ou modifie
des fichiers malveillants dans des répertoires cachés d'espaces de travail de
projet destinés aux assistants de codage IA et aux environnements de
développement intégrés (IDE) (.claude/, .vscode/, .cursor/, etc.) ». GTIG
explique pourquoi : ces dossiers permettent au logiciel malveillant de se fondre
« dans le bruit ordinaire du développement » et d'éviter les endroits que la
détection de poste surveille, comme les clés de registre et /etc/cron.*. Votre
éditeur d'EDR n'a pas livré de règle pour un nouveau fichier dans .cursor/,
parce que jusqu'à cette année ce dossier contenait des préférences d'éditeur.
L'assistant reçoit un fichier de configuration, et les fichiers de
configuration sont des instructions. Depuis ces mêmes répertoires cachés,
DUSTMAKER « utilise des fichiers de configuration malveillants … pour ordonner
à l'assistant IA d'exécuter des commandes ou des scripts arbitraires (comme
setup.mjs) lors d'interactions de développement ordinaires. Cela contraint
effectivement le modèle IA à exécuter des commandes pour le compte de l'attaquant
à l'insu du développeur ». L'assistant a lu la configuration de son espace de
travail, ce qui est son travail, et la configuration a nommé un script à
exécuter. Aucune faille exploitée dans cette phrase.
Et l'API d'audit efface la piste d'audit. Le logiciel malveillant masque ses tâches CI sous des noms à thème IA comme « Copilot Setup », puis émet des appels d'API automatisés pour retirer les journaux d'exécution des workflows de l'interface GitHub.
Toutes les cinq ont fonctionné comme prévu
Vous n'avez aucun bogue à signaler ici. Le scanner a appliqué sa politique de sécurité, ce pour quoi vous le payez. Le vérificateur a validé une signature qui était valide. L'assistant a chargé la configuration de son espace de travail, c'est la fonctionnalité. L'agent de poste a surveillé les chemins qui comptaient avant que les agents de codage n'aient des répertoires de configuration. Chacun a fait son travail sur l'entrée qu'il a reçue, et c'est UNC6780 qui a choisi l'entrée.
L'évasion ordinaire réclame un verdict erroné : empaqueter le binaire, découper la chaîne, encoder l'URL, espérer que l'analyse revienne propre. DUSTMAKER obtient ce qu'il veut d'un verdict juste, ou d'aucun verdict du tout.
Toute défense de la forme lire l'artefact, se forger une opinion se trouve à portée de cela. Un modèle de langage dans le fauteuil du lecteur élargit cette portée, car un modèle transporte sa propre liste de choses qu'il ne fera pas, et cette liste est publique, documentée, et accessible à quiconque sait taper un commentaire. L'industrie a passé deux ans à durcir les modèles contre le fait de se laisser convaincre de dire oui. UNC6780 les convainc de ne rien dire.
Posez donc une autre question aux contrôles de votre pipeline agentique : lesquels doivent lire du contenu écrit par l'attaquant pour faire leur travail, et que reste-t-il debout une fois ceux-là mis de côté.
Des contrôles avec lesquels on ne discute pas
Bromure Agentic Coding exécute chaque agent de codage dans une VM Linux virtualisée matériellement sur votre Mac, avec tous les contrôles de sécurité du côté hôte de cette frontière. Ce qui compte face à une chaîne comme celle-ci, c'est ce que ces contrôles prennent en entrée.
Le filtre d'âge lit une horloge. Le proxy hôte reconnaît les requêtes vers les grands registres de paquets et applique la politique de chaîne d'approvisionnement de l'espace de travail avant qu'un octet n'atteigne la VM. Le filtre d'âge, la seule couche active par défaut et réglée sur un minimum de deux jours, refuse les versions plus jeunes que le seuil. Il réécrit pour cela la liste des versions du registre, de sorte que du point de vue de l'agent une version trop fraîche n'existe pas encore ; une récupération directe épinglée revient en HTTP 451 dont le corps indique l'âge réel du paquet. Le paquet lui-même n'est jamais lu. Un bloc de commentaires conçu pour faire dérailler un modèle de langage ne déplace aucune date de publication, et les forks trojanisés d'UNC6780 sont par construction des publications fraîches. npm, PyPI, Cargo, RubyGems et Packagist portent tous des dates de publication par version, donc le filtre les couvre.
Un classifieur n'a aucune politique à invoquer. Le détecteur de code source
de Bromure note les segments tool_result que l'agent renvoie en flux au
modèle — contenus de fichiers, pages web et sorties de commandes — à l'aide d'un
modèle PromptGuard local de la famille DeBERTa tournant en ONNX sur votre Mac.
C'est un classifieur de séquences, pas un modèle génératif. Placé devant le bloc
de commentaires de DUSTMAKER, il ne compose aucune réponse, ne pèse aucune
question sur la licéité de répondre, et ne refuse rien. Il émet un nombre entre
zéro et un, et un texte qui s'ouvre sur une fausse dérogation système annonçant
des consignes de sécurité suspendues est exactement la forme qui fait monter ce
nombre. Par espace de travail, vous choisissez ce que fait une détection :
journaliser, demander ou bloquer. Un blocage renvoie 451, et le modèle ne voit
jamais le contenu.
Autre chose que l'agent lit la configuration de l'espace de travail. Un
fichier dans .claude/ qui dit à l'assistant d'exécuter setup.mjs, c'est la
porte dérobée par fichier de règles, et elle a son propre détecteur : une passe
heuristique déterministe pour l'Unicode caché, les motifs de méta-instructions,
les chemins d'identifiants et les constructions curl-vers-shell, plus un
classifieur ModernBERT affiné pour les instructions malveillantes qui ne
correspondent à aucun motif fixe. Les deux tournent dans le proxy, sur l'appareil,
sur les fichiers d'instructions extraits de l'invite système, là où rien à
l'intérieur de la VM ne peut les éteindre. Les deux sont des bascules par espace
de travail, et chacun veut un téléchargement de modèle la première fois que vous
l'activez. Ce téléchargement, ce sont les cinq minutes que cette histoire vous
demande.
Un voleur d'identifiants a besoin d'identifiants. DUSTMAKER existe pour
récolter des secrets dans les environnements de développement, et un espace de
travail Bromure n'en contient aucun. Bromure remplace chaque identifiant que vous
configurez par un faux préservant la structure, dérivé de la vraie valeur et d'un
sel propre à l'installation : sk-ant-api03-brm-…, un jeton ghp_ de la bonne
longueur, brm-mcp_…, brm-k8s-…. Ces faux vont dans les variables
d'environnement et dans ~/.git-credentials, ~/.docker/config.json,
~/.kube/config et ~/.aws/config, soit exactement la liste qu'énumère un
voleur. Vos vraies valeurs restent chiffrées sur le Mac, et le proxy hôte les
substitue sur le fil, cantonnées à l'hôte de destination pour lequel chacune a été
émise. Les octets des clés privées SSH n'entrent jamais dans la VM ; seules les
signatures franchissent la frontière. Aucune bascule ne gouverne tout cela, parce
que le proxy est l'unique route de la VM vers le réseau.
Les faux servent aussi de fils-pièges. Un faux jeton a une seule destination légitime. Le proxy analyse chaque requête sortante, en-têtes et corps, à la recherche d'un faux parti ailleurs. En cas de correspondance, il refuse la requête sans transmettre un octet, met la VM en pause sur-le-champ, et inscrit une ligne rouge Courtage d'identifiants dans la Security Timeline. Il marque l'espace de travail comme compromis, et le lancement suivant vous oblige d'abord à effacer le disque et l'image de home. Vous ne faites aucune rotation ensuite, parce que le voleur tenait un leurre et que le leurre n'est jamais sorti.
Le registre vit sur votre machine, hors de portée de l'API qu'appelle le
logiciel malveillant. Avec le traçage sur Activité seulement, le proxy écrit
une ligne de métadonnées par requête quittant la VM, sans corps.
bromure-cli trace hostnames affiche chaque hôte distinct contacté par l'espace
de travail avec les compteurs, et bromure-cli trace leaks nomme la destination
après une alerte de compromission. Un attaquant détenant un jeton GitHub peut
vider un historique de workflows en quelques appels d'API. Vider cette trace
suppose d'atteindre votre Mac.
Deux réglages, cet après-midi
Ouvrez le volet Supply Chain de l'espace de travail et vérifiez que le filtre d'âge est actif avec un seuil vivable. Deux jours est la valeur par défaut, et c'est le contrôle le moins cher dont vous disposiez contre un fork trojanisé fraîchement publié. Ouvrez ensuite Prompt Injection et activez les deux détecteurs ; chacun télécharge son modèle une fois, et après cela l'analyse est locale et gratuite.
Une règle qui rétrécit la question
Dans Guardrails, mettez Unmatched traffic sur Deny et listez ce
dont le travail a besoin : allow web api.github.com,
allow web registry.npmjs.org, default deny. Un voleur qui ne peut pas
joindre son serveur de commande est un fichier sur un disque que vous êtes sur
le point de jeter, et l'enregistrement pousse la règle vers les sessions en
cours sans redémarrage.
L'absence bat l'évaluation
Nous arrivons sans cesse au même endroit par des chemins différents. Un proxy de sortie qui faisait confiance à un nom que l'agent pouvait écrire. Un garde-fou de commandes qui lisait bash autrement que bash. Une passerelle IA dont la vérification de clé ratée retombait sur un objet d'authentification vide. Dans chaque cas, un composant faisait honnêtement son travail d'évaluation de quelque chose, et l'évaluation s'est cassée.
DUSTMAKER aiguise l'argument, car il ne demande aucune évaluation cassée. Il demande qu'une évaluation ait lieu sur un contenu écrit par UNC6780. Donnez un fichier à un lecteur et le lecteur s'en fait une idée ; qui a fourni le fichier règle le reste.
L'évaluation est une primitive plus faible que l'absence, et nous ne cessons de confier à l'évaluation le travail que l'absence fait gratuitement. On ne discute pas avec une date de publication, et une probabilité n'a aucune disposition à se rétracter. Un voleur d'identifiants tournant à pleins privilèges dans une VM jetable, parcourant tous les fichiers de configuration qu'il connaît, en ressort avec une poignée de leurres et une socket qu'il ne peut pas contourner.
Mettre un modèle dans votre pipeline de revue était le bon choix. Assurez-vous que les contrôles qui arrêtent les choses sont ceux à qui rien dans le dépôt ne peut parler. Installez Bromure Agentic Coding et donnez à votre agent des contrôles qui n'ont jamais à lire le fichier de l'attaquant.