Sa tâche était une issue, son token pouvait lire toute l'organisation
GitLost, de Noma Security, a montré un inconnu non authentifié ouvrant une issue publique sur GitHub et amenant l'agent IA de GitHub à publier le contenu d'un dépôt privé en commentaire public. L'injection de prompt a fait les gros titres. Le token de l'agent, dimensionné pour toute l'organisation au lieu de la seule issue qu'il triait, a fixé jusqu'où la fuite pouvait aller. Cet écart entre ce dont une tâche a besoin et ce que l'environnement détient est la partie à retenir, et celle que vous pouvez concevoir autrement quand vous hébergez l'agent vous-même.
Un inconnu non authentifié a ouvert une issue sur un repo GitHub public, a écrit un paragraphe, et a attendu. L'agent IA de GitHub a lu l'issue, s'est promené dans les dépôts privés de l'organisation, et a publié un README privé en commentaire public. Le paragraphe était le déclencheur. Le token de l'agent, dimensionné pour toute l'organisation au lieu de la seule issue devant lui, est la raison pour laquelle la fuite est allée si loin.
L'équipe de recherche de Noma Security a monté une organisation sur
GitHub comme beaucoup d'équipes le font aujourd'hui : une poignée de
dépôts publics, plusieurs privés, et GitHub Agentic Workflows branché
pour absorber les corvées. Les GitHub Agentic Workflows sont des
instructions en Markdown ordinaire que GitHub Actions confie à un agent
IA, adossé à Claude ou Copilot, pour qu'il trie les issues, réponde aux
questions et ouvre des pull requests au nom de l'équipe. Puis les
chercheurs ont joué l'attaquant. Ils ont ouvert une issue d'apparence
banale dans l'un des dépôts publics, glissé quelques phrases de plus
dans le corps du texte, et laissé le workflow tourner. L'agent a lu
l'issue, récupéré le contenu d'un README.md d'un dépôt privé, et l'a
collé dans un commentaire public où n'importe qui pouvait le lire.
L'attaquant n'a utilisé aucun mot de passe, aucune clé volée, aucun code d'exploit, et il n'y a pas de CVE. Noma appelle la technique GitLost, l'a signalée à GitHub, et a publié avec l'accord de l'entreprise. Toute la charge utile était de la prose anglaise posée dans un champ que l'agent était construit pour lire.
L'issue qui a répondu avec un repo privé.
La mécanique est courte, et c'est ce qui la rend digne d'être dessinée. Un workflow se déclenche sur un événement, comme une issue ouverte ou assignée. L'agent lit le titre et le corps de l'issue comme sa tâche. Enfouies dans ce corps se trouvaient des instructions demandant à l'agent de récupérer le README d'un dépôt privé et de le publier en commentaire. GitHub avait des garde-fous devant tout cela : sandboxing, tokens en lecture seule par défaut, nettoyage des entrées, et une passe de détection de menaces sur le texte. Noma a essayé des variantes jusqu'à ce que l'une passe. Préfixer la requête malveillante du mot « Additionally » (« De plus ») a suffi à franchir le filtre, parce que le modèle l'a lue comme une tâche supplémentaire plutôt que comme une requête à refuser. Un changement d'un mot a fait passer l'injection de l'autre côté de la ligne.
Reformuler bat le filtre.
Un filtre qui lit le corps d'une issue et décide s'il contient une attaque devine l'intention à partir de la formulation, et la formulation a une réserve infinie de variantes. Noma n'a pas cassé le modèle ni trouvé un bug mémoire. Ils ont reformulé la même requête jusqu'à ce que le classifieur la note sous son propre seuil, et « Additionally » était la formulation qui a atterri.
C'est la propriété structurelle des agents à outils que nous avons décrite la semaine dernière : un agent lit ses instructions et les données qu'il récupère comme un seul flux plat de tokens, et il infère quelle partie est une commande à partir du ton et de la position, comme une personne qui parcourt un texte. Le corps d'une issue est de la donnée. L'injection est le geste qui donne à une donnée non fiable la forme d'une commande et parie que le modèle agira dessus. La détection aide et mérite d'être exécutée, et elle ratera : un classifieur a un seuil, et un attaquant aux tentatives illimitées sonde jusqu'à ce qu'une formulation passe en dessous.
L'écart qui a dimensionné la fuite.
Une partie de GitLost survit à n'importe quel filtre que GitHub livrera ensuite. La tâche du workflow était de trier une issue dans un dépôt public. Le token que GitHub Actions plaçait dans l'environnement de ce workflow avait accès en lecture à chaque dépôt public et privé de l'organisation, parce que les équipes accordent cette largeur pour que l'agent puisse tirer du contexte entre dépôts. L'attaquant a choisi la cible ; la portée du token a fixé la limite des dégâts. Reformulez l'attaque de cent façons et cette limite reste la même : tout ce que le token peut voir.
La propre recommandation de Noma pointe la même couture. Leur conseil aux défenseurs est de limiter le token au seul dépôt que le workflow trie plutôt qu'à toute l'organisation. Ce conseil concède que l'injection atterrira parfois, et que quand elle atterrit, le rayon d'impact devrait être de la taille de la tâche plutôt que de la taille du compte.
Le canal d'exfiltration était le métier de l'agent.
Le README privé a quitté l'organisation par un commentaire public, ce qui est une chose que l'agent est censé pouvoir faire. Commenter les issues est sa fonction. Rien sur le fil ne ressemblait à un vol : aucun endpoint étrange, aucun blob encodé sortant par une porte dérobée. Un moniteur réseau guettant du trafic malveillant aurait vu l'agent publier un commentaire, ce qu'il fait toute la journée. Quand le canal d'exfiltration est une capacité sanctionnée, la défense qui paie est de contraindre ce que l'agent peut atteindre en premier lieu.
Là où vous pouvez changer l'architecture.
Deux choses de GitLost sont hors de votre portée. Le bug appartient à GitHub, et GitHub y travaille. Et l'agent tournait sur les serveurs de GitHub, à l'intérieur de GitHub Actions, où aucun produit que vous installez ne se trouve sur le chemin. Bromure Agentic Coding tourne sur le Mac d'un développeur. Il n'est pas devant le workflow côté serveur de GitHub et ne prétend pas l'être. Si votre seule exposition à cette classe de problème est un agent hébergé que quelqu'un d'autre opère, le levier dont vous disposez est celui que Noma a nommé : réduire la portée du token.
La leçon transférable s'adresse au nombre croissant d'équipes qui font tourner des agents de codage sur des machines qu'elles contrôlent, où l'architecture est la vôtre. Deux principes traversent depuis GitLost, et aucun ne dépend d'attraper l'injection. Gardez l'environnement mince, pour qu'un agent détourné hérite de peu de choses qui vaillent d'être prises. Limitez l'identifiant à la tâche, pour que la portée d'une compromission soit de la taille du travail plutôt que de la taille du compte. Bromure Agentic Coding est un arrangement de ces principes.
Bromure Agentic Coding fait tourner votre agent de
codage, Claude Code, Codex ou Grok, à l'intérieur d'une VM Linux
jetable par profil : son propre noyau, son propre système de fichiers,
sa propre pile réseau, à un hyperviseur de distance de votre Mac sur le
framework de virtualisation d'Apple. Un profil est un périmètre de
travail cohérent, un client ou un service. Les vrais identifiants
n'entrent jamais dans cette VM. Bromure les détient sur l'hôte derrière
un broker et expédie au système invité de fausses valeurs qui semblent
réelles aux outils qui les lisent ; un proxy sur votre Mac substitue le
vrai secret au stub sur le fil au moment où la requête part, et
le bac à sable qui détenait la clé
détaille le mécanisme. Un agent qu'on convainc d'exécuter cat sur un
fichier d'identifiants trouve un substitut, parce que la valeur qu'il
voulait n'a jamais été de son côté de la frontière.
Le token que l'agent peut effectivement dépenser est limité et expirant, si bien qu'une fuite est un usage étroit et borné dans le temps plutôt qu'un droit permanent. Toute la zone de travail est une VM qui disparaît quand vous fermez la session. Faites passer la forme GitLost par cet arrangement et l'injection peut toujours atterrir, parce que l'isolation ne détrompe pas un modèle. Un agent convaincu d'exfiltrer tend la main vers un identifiant et trouve un stub, dépense un token qui ne couvre que le profil dans lequel il travaillait, et se tient dans une boîte sans chemin vers le reste de votre machine. La portée de la compromission est la taille de la tâche.
Gardez l'environnement mince
Un agent détourné ne peut livrer que ce que son environnement détient. Des stubs dans le système invité et les vrais secrets sur l'hôte font que l'injection qui atterrit trouve des substituts là où elle attendait des clés.
Limitez l'identifiant à la tâche
Le conseil de Noma pour les workflows GitHub relève du même principe : un token qui couvre un dépôt plafonne les dégâts à un dépôt. Portée et expiration transforment une fuite en un événement étroit et borné dans le temps.
Rendez la boîte jetable
Quand la zone de travail est une VM qui s'évapore à la fermeture, la persistance n'a nulle part de durable où s'installer et le rayon d'impact se termine avec la session.
Supposez qu'il sera injecté
La détection mérite d'être exécutée et elle ratera. Concevez pour que le résultat d'un raté soit survivable, plutôt que de parier sur l'interception de chaque formulation.
Ce que cela laisse debout.
Limiter la portée ne rend pas un agent sûr à pointer vers un vrai secret. Si vous placez un identifiant vivant à l'intérieur de la VM et que l'agent se fait convaincre de le lire, aucun hyperviseur ne le dé-lit ; le changement porte sur ce que l'agent peut atteindre, pas sur le fait qu'un modèle trompé reste trompé. Le problème d'exfiltration que Noma a souligné a une part que l'isolation seule ne ferme pas non plus : un agent qui peut publier un commentaire, ouvrir une PR ou envoyer un message peut faire sortir des données par ce canal sanctionné, et la portée décide de la quantité de données à sa portée à déplacer, pas de l'existence du canal. Et GitLost lui-même appartient à GitHub. Mettez à jour quand ils corrigeront, et réduisez la portée de vos tokens de workflow d'ici là, parce que c'est le levier que la plateforme vous tend.
Où que vous fassiez tourner un agent, les chercheurs continueront de signaler les injections, et la portée de l'identifiant dans l'environnement de l'agent continuera de déterminer si chacune finit en quasi-incident journalisé ou en dépôt privé sur une page publique. Le correctif de Noma et l'architecture de Bromure pointent dans la même direction : donnez à l'agent la portée dont la tâche a besoin et rien de plus large.
Bromure Agentic Coding fait tourner Claude Code, Codex et Grok dans des VM Linux jetables sur Apple Silicon, avec les vrais identifiants détenus sur l'hôte derrière un broker et substitués sur le fil, une détection d'injection de prompt sur les entrées de l'agent, et chaque appel écrit dans une trace que l'agent ne peut pas éditer. C'est gratuit, open source, et disponible dès aujourd'hui sur bromure.io. Avec nos remerciements à Noma Security, dont l'analyse de GitLost a inspiré celle-ci.