Retour à tous les articles
Publié le · par Renaud Deraison

Pourquoi Bromure Agentic Coding n'est pas un bac à sable

Un bac à sable demande au développeur de troquer la vitesse qui rend un agent de codage digne d'être lancé — pré-approuver chaque dépendance, maintenir une liste blanche de domaines, ne jamais toucher un paquet que l'organisation n'a pas validé. Alors les développeurs le désactivent. Bromure Agentic Coding refuse ce troc. Il ne contraint pas ce que l'agent fait ; il trace une seule ligne dure au niveau de l'hyperviseur et vous laisse tout faire à l'intérieur. Voici l'argument fondateur expliquant pourquoi une frontière vaut mieux qu'un bac à sable, et les trois garanties que la frontière rend vraies : aucun identifiant à voler, des tokens larges rétrécis au passage du fil, et des attaques de la chaîne d'approvisionnement arrêtées avant que le tarball n'atterrisse — plus la quatrième que la ligne rend désormais vraie : les injections de prompt attrapées dans le contenu que l'agent lit, avant que le modèle ne leur obéisse.

Un bac à sable propose un troc : abandonnez une part de ce qui rend un agent de codage utile, et en échange il vous gardera en sécurité. Les développeurs refusent ce troc à chaque fois — ils désactivent le bac à sable, ou ne l'activent jamais — et ils ont raison. Le travail d'un agent, c'est d'avancer vite à travers un territoire désordonné et non validé. Bromure Agentic Coding ne contraint pas cela. Il trace une seule ligne dure, au niveau de l'hyperviseur, et vous laisse faire tout ce que vous voulez à l'intérieur.

Un billet fondateur — écrit une fois, pour que les autres y renvoient. Pas à propos d'un incident. À propos de pourquoi nous avons construit Bromure Agentic Coding comme nous l'avons fait, et pourquoi « c'est un bac à sable » est la description que nous ne cessons de corriger.

Un développeur n'est pas un sysadmin.

La raison de mettre un agent de codage sur votre machine, c'est la vitesse — le genre concret : tirer un paquet que personne dans votre entreprise n'a validé, à onze heures du soir, pour voir si une idée tient. Essayer la bibliothèque, lancer son exemple, la jeter si elle ne convient pas. Ce n'est pas un défaut à discipliner chez les gens. C'est ça, le flux de travail, et toute la raison pour laquelle l'agent vaut la peine d'être là.

Donc tout modèle qui vous fait pré-approuver chaque dépendance, ou qui fait que quelqu'un doit maintenir une liste des domaines que l'agent peut atteindre, est en guerre avec la chose qu'il protège. Il ralentit la seule activité qu'il a été déployé pour permettre — et un contrôle qui gêne la livraison n'a qu'un seul destin : il est désactivé. Un contrôle qu'un développeur désactive pour faire son travail n'a jamais été un contrôle.

« Faites tourner un miroir privé et validé » manque le point de la même façon : les paquets qui comptent pour l'expérimentation sont ceux que personne n'a encore validés. Un miroir de dépendances approuvées est un miroir des idées d'hier.

Donc la question n'est pas comment empêcher les développeurs de toucher au code non validé. Ils le doivent ; c'est le travail. C'est comment les laisser toucher à tout, librement, sans que leur trousseau fasse partie du marché.

Le bac à sable conçu pour la production ne convient pas à l'établi.

Le premier réflexe est un bac à sable réseau — les conteneurs durcis, ceux de NVIDIA, les recettes Docker-Compose qui circulent. La forme est toujours la même : énumérer les hôtes que l'agent peut atteindre, refuser le reste. Ça marche à merveille quand l'agent a un travail connu et étroit. Un agent de production qui parle à trois services internes et un point de terminaison de modèle vit derrière une liste blanche pour toujours, parce que la liste est courte et cesse de changer.

L'idéation n'a pas de liste courte, et elle ne cesse jamais de changer. Personne ne veut maintenir une liste blanche de chaque registre, CDN, hôte Git, et API ponctuelle qu'une expérience pourrait atteindre — elle n'est jamais finie, elle grandit chaque après-midi, et le jour où elle bloque quelque chose de légitime est le jour où le développeur la désactive pour se débloquer. La liste blanche n'a pas tort ; elle sécurise un agent dont la portée est déjà connue. Toute la valeur de l'établi, c'est que la portée n'est pas encore connue.

Prenons un après-midi concret. Un développeur a des fichiers de config Node qui ont gonflé à des dizaines de mégaoctets, et le parseur YAML qu'il utilise s'étrangle dessus. Il y a plusieurs candidats — js-yaml, yaml, yaml-js — et le seul moyen de savoir lequel survit à un fichier de 40 Mo sans faire exploser le tas, c'est d'installer les trois et de leur jeter le fichier. Ouvrir un ticket pour faire entrer trois bibliothèques dans le miroir privé afin qu'elles puissent être testées est exactement à l'envers : le développeur veut d'abord tester et promouvoir le gagnant dans le miroir, pas l'inverse. La pré-validation est le portail que l'expérience existe pour franchir.

Il y a un problème plus discret en dessous. Ces outils durcissent l'agent en production — déployé, cadré, supervisé. Mais une compromission de la chaîne d'approvisionnement atterrit sur le portable du développeur, en pleine expérience, avec de vrais identifiants dans ~/.aws et ~/.npmrc parce que c'est là que les développeurs les gardent. Le modèle est le plus fort là où les attaques ne sont pas, et absent là où elles sont.

Le bac à sable du chat et de la souris perd la deuxième manche.

L'autre instinct est de laisser l'agent sur l'hôte et d'emprisonner le processus — empêcher le processus claude de lire ~/.ssh et ~/.aws. Ça semble étanche, jusqu'à ce que vous vous rappeliez que le travail de l'agent est d'écrire du code, et que le code tourne sur la même machine.

L'agent échafaude un projet. Puis vous — ou l'agent, ou un second outil — lancez npm install dans le dépôt qu'il vient d'écrire. Ce npm install n'est pas le processus emprisonné. Son hook postinstall lit ~/.aws/credentials comme n'importe quel autre programme sur votre portable, parce que c'est exactement ce qu'il est : un autre programme, qui partage l'unique système de fichiers et l'unique trousseau avec tout le reste de ce que vous lancez.

VOTRE PORTABLE — un système de fichiers, un trousseauPRISON DE PROCESSUSclaude✗ lit ~/.ssh✗ lit ~/.awsbloqué — semble étanche./repo — écrit par l'agentpackage.json "postinstall": "node x.js"SECOND SHELL — non emprisonné$ npm install lance postinstallun processus que la prison n'a pas nomméTROUSSEAU~/.aws/credentials~/.ssh/id_rsa~/.npmrcvrais tokens✗ la prison refuse ce cheminlit les vrais creds — personne n'a emprisonné ça
La faille du chat et de la souris. Une prison de processus empêche le processus claude d'atteindre le trousseau (le chemin en pointillés, refusé). Mais la sortie réelle de l'agent — un dépôt avec un hook postinstall — tourne dans un processus frère dont la prison n'a jamais entendu parler. Ouvrez un second shell, lancez npm install, et son postinstall lit ~/.aws/credentials librement et exfiltre, parce que sur un même hôte chaque processus partage un seul système de fichiers et un seul trousseau. La prison a tracé sa frontière autour de la mauvaise chose : le danger n'a jamais été le processus nommé, c'était la machine partagée.

La prison a tracé sa frontière autour d'un processus. Le danger n'a jamais été le processus ; c'était que chaque processus sur la machine partage un seul système de fichiers et un seul trousseau. Alors vous rapiécez — emprisonnez le shell aussi, puis node, puis le gestionnaire de paquets — et l'attaquant continue de trouver une porte que vous n'avez pas verrouillée, parce que sur un même hôte il y a toujours un autre processus, un autre chemin vers les mêmes secrets. C'est ça, le jeu, et la maison a toujours une autre porte.

Tracez la ligne une fois, avec l'hyperviseur.

Bromure cesse de jouer en déplaçant la frontière d'un cran vers le bas. L'agent, les shells qu'il lance, les paquets qu'il installe, et tout le code que ces paquets exécutent vivent tous à l'intérieur d'une VM Linux par profil. Vos vrais identifiants n'y entrent jamais.

La différence, c'est le genre de ligne. Une prison de processus est une politique à propos d'un processus, et un processus frère la contourne. La frontière de la VM est le mur entre l'invité et l'hôte, imposé par l'hyperviseur — le même mur qui empêche une VM de lire la mémoire d'une autre. Il n'y a pas d'appel système pour le franchir. Le code à l'intérieur ne peut pas raisonner jusqu'à votre trousseau, parce que le trousseau n'est pas du tout dans son monde.

Et à l'intérieur de cette ligne, vous êtes libre. Installez le paquet non validé. Lancez son postinstall. Laissez l'agent réécrire votre config de shell, remplir le disque, casser la chaîne d'outils. La VM est jetable et n'a jamais rien contenu d'important. Cette liberté est tout le propos — exactement ce qu'un bac à sable retire et ce qu'une frontière nette rend. On n'obtient pas la sécurité en rendant l'établi moins utile ; on l'obtient en faisant de l'établi un endroit où rien de précieux n'était dans la pièce au départ.

C'est sur cette même ligne que trois garanties cessent d'être des conseils que l'agent peut outrepasser et deviennent des faits imposés en dessous de lui — parce que tout ce que la VM fait vers l'extérieur doit la franchir.

Trois choses que la ligne rend vraies.

VM PAR PROFIL — installer, lancer, casser n'importe quoiagent · shells lancés · npm / pip · code postinstall non fiablele FS ne contient que des leurres — aws_secret = stub-… _authToken = stub-… id_rsa = stub-…rien ici n'est réel, donc rien ici ne vaut d'être volérécupérer un paquetutiliser un identifiantpush / drop / deleteFRONTIÈRE HYPERVISEUR — la seule ligne que le code à l'intérieur ne peut franchir① Bloquer les paquets malveillantsscan : OSV + socket.devcarence : < 2 jours retenule tarball malveillant n'atterrit jamais② Aucun cred à volerstub-token ⇄ real tokenéchangé au passage du filun balayage de l'hôte trouve des leurres③ Demander avant de muterlecture passe · écriture pausedemande sur l'hôtevous voyez l'appel littéralHÔTE — vrais tokens, derrière le courtier~/.aws · ~/.ssh · ~/.npmrc — n'entrent jamais dans la VM, injectés au fil seulement, pour un appel autorisé
Une frontière, trois contrôles, imposés sous l'agent. À l'intérieur de la VM l'agent fait ce qu'il veut. Mais chaque franchissement est médiatisé par l'hyperviseur : une récupération de paquet est scannée (OSV + socket.dev) et retenue si elle est plus jeune que le délai de carence ; un usage d'identifiant rencontre un leurre que le proxy de l'hôte échange contre le vrai token au passage du fil puis ré-échange en sortie ; une écriture qui change d'état marque une pause pour une demande sur l'hôte. Le vrai trousseau se trouve sous la ligne et n'entre jamais dans la VM. L'agent ne peut contourner aucun de ces contrôles, parce qu'il n'y a pas de chemin à travers la frontière sinon par eux.

Aucun identifiant à voler — le secret n'a jamais été dans la pièce.

Les vrais tokens restent sur l'hôte. La VM reçoit des leurres : des fichiers d'identifiants syntaxiquement valides dont le contenu ne signifie rien sur l'internet public. Quand l'agent fait un appel légitime qui a besoin d'un vrai token, un proxy de l'hôte échange le leurre contre le vrai secret au passage du fil et le ré-échange en sortie de la réponse. Une dépendance compromise qui balaie le système de fichiers à la recherche de ~/.aws/credentials, ~/.npmrc ou id_rsa trouve des espaces réservés. C'est l'échange de token : l'identifiant existe, l'agent l'utilise pour ce à quoi il sert, et la copie qui pourrait être volée n'existe nulle part que le monde de l'agent puisse atteindre.

Rétrécir le token large — demander avant l'usage, demander avant de muter.

Les vrais tokens sont généralement plus larges que la tâche. Le courtier maintient les octrois éphémères et cadrés, et — la partie qui justifie son existence — traite une lecture et une écriture différemment. Une lecture passe. Un appel qui change d'état — un git push, un DROP TABLE, un Terminate* AWS — marque une pause à la frontière et vous demande, sur l'hôte, en montrant l'opération littérale, pas un résumé écrit par l'agent.

Cela change ce que signifie un token large. Un qui pourrait supprimer la production ne peut le faire que lorsqu'un humain a vu l'appel exact et a dit oui ; la portée imprimée sur l'identifiant cesse d'être le rayon d'explosion. L'agent ne peut pas s'auto-approuver, rétrograder le mode, ni lire l'octroi — la décision vit de l'autre côté de la ligne. Quand un agent a supprimé une base de production en neuf secondes, le principe était le même : la chose qui veut exécuter la commande ne devrait pas être la chose qui décide qu'elle est sûre.

Ne soyez pas le premier à l'apprendre — la chaîne d'approvisionnement arrêtée à la porte.

Le meilleur moment pour arrêter un paquet empoisonné, c'est avant qu'il n'atterrisse. Chaque récupération franchit la frontière, donc le proxy la scanne — OSV pour les CVE connues, socket.dev pour ce que les bases de données n'ont pas encore attrapé : scripts d'installation malveillants, typosquats, la compromission publiée il y a une heure. Et il impose un délai de carence : toute publication des deux derniers jours (réglable) est tout simplement non installable le temps que l'écosystème rattrape son retard. Toute la fenêtre d'un ver, c'est l'écart entre la publication et le retrait ; refuser les paquets vieux d'un jour, c'est refuser d'être le canari. Les hooks postinstall sont retirés du tarball à l'entrée, le hash corrigé pour que l'installation se vérifie quand même — si bien que le paquet qui atterrit atterrit inerte. Rien de tout cela ne demande au développeur de valider quoi que ce soit. Il tire ce qu'il veut ; la frontière est ce qui attend.

Là où tout le reste s'arrête

La plupart des outils couvrent une seule couche. Bromure les couvre toutes.

Isolation, garder les secrets hors de l'agent, encadrer leur usage, analyser la chaîne d'approvisionnement, intercepter l'injection de prompt — le domaine a tendance à n'en choisir qu'une. Voici le même modèle de menace appliqué aux outils vers lesquels on se tourne, et là où chacun s'arrête.

Protection
Dev ContainerVS Code
nonokernel sandbox
agent-vaultoctokraft
Agent VaultInfisical
Docker SandboxesmicroVM
BromureAgentic Coding
Frontière d'isolation
Là où s'arrête le rayon d'impact
Même conteneur, noyau partagé
Allowlists noyau, pas de noyau propre
L'agent s'exécute sur place
Proxy seul ; agent non isolé
microVM, son propre noyau
VM matérielle, son propre noyau
Garder les secrets hors de l'agent
Peut-il jamais lire le vrai identifiant ?
Transfère l'agent SSH + creds git
Bloque les fichiers de clés ; en relaie certains
Injectés par pipe ; aucun accès en lecture
Le proxy les attache sur le fil
Le proxy de l'hôte injecte les en-têtes
Stub échangé sur le fil
Portée et approbation des identifiants
Limites par usage, lecture seule, expiration, accord
Aucune portée par usage
Flux d'approbation + filtre d'egress
TTL par secret ; bloque les shells
Filtre d'egress par endpoint
Allowlist de domaines ; le code dans la VM peut quand même l'utiliser
Accord par destination + TTL
Analyse de la chaîne d'approvisionnement
Attraper les paquets malveillants / vulnérables
Aucune analyse du registre
Signature seule, pas d'analyse de paquets
Hors périmètre
Hors périmètre
Aucune analyse de paquets
Age-gate, OSV, socket.dev
Détection d'injection de prompt
Analyse le contenu non fiable et les fichiers de règles
PromptGuard + ModernBERT
Piste d'audit
Enregistrer ce que l'agent a fait
Logs du conteneur seuls
Audit local immuable
Journalisation des requêtes
Journalisation des requêtes
Trace de session complète, chiffrée
Inventaire de la chaîne d'approvisionnement(Enterprise)
Un relevé de chaque paquet récupéré
Chaque dépendance + verdict, cherchable
Usage de tokens(Enterprise)
Quels fichiers consomment le plus de tokens
Par fichier, repo et modèle
Total — intégré, appliqué Partiel — limité ou optionnel Aucun — non traité

Masquer un jeton n'est pas la même chose que gouverner son usage. Docker Sandboxes garde la valeur réelle hors de la VM, mais son proxy attache tout de même cet identifiant à chaque requête sortante de la sandbox ; un paquet compromis installé à côté peut donc le dépenser contre un service autorisé sans jamais le voir. Seul Bromure analyse le paquet avant son exécution et encadre chaque usage — accord, lecture seule, un TTL — en appliquant les cinq contrôles à une frontière que l'agent ne peut contourner.

Compilé à partir de la documentation publique de chaque projet, juin 2026. Ici, agent-vault désigne octokraft/agent-vault (injection de secrets par pipe), à distinguer de l'Agent Vault d'Infisical (proxy d'identifiants HTTP). Docker Sandboxes est un aperçu expérimental dont les identifiants relayés restent utilisables par tout ce qui tourne dans la VM. L'inventaire des paquets sur toute la flotte et les ventilations de l'usage des tokens sont fournis par Bromure Enterprise Manager. Ces outils évoluent vite — quelque chose d'obsolète ? Dites-le-nous.

La quatrième chose : une instruction dans les données n'est pas un ordre.

Les trois garanties ci-dessus partagent une hypothèse qui mérite d'être mise au jour : elles défendent toutes contre du code qui prend quelque chose — un identifiant, un token, l'occasion qu'avait un tarball frais de s'exécuter. Il existe une attaque qui ne prend rien. Elle se contente de dire à l'agent quoi faire. Une ligne enfouie dans un README que l'agent lit, une chaîne dans une page récupérée, une phrase dans la sortie d'un outil, une directive cachée dans le CLAUDE.md que l'agent traite comme des ordres permanents — le modèle l'ingère comme du contexte et lui obéit comme à une instruction. Divulgue le fichier. Affaiblis la vérification. Saute le test. Un bac à sable n'a d'opinion sur rien de tout cela, parce que rien n'a franchi un mur qu'il surveille : l'instruction est arrivée comme donnée, dans du contenu que l'agent était censé lire.

Mais elle a bel et bien franchi la ligne — tout ce que le modèle voit la franchit. Alors depuis la 2.4.0, la frontière la lit d'abord, sur l'appareil, côté hôte. Un classifieur PromptGuard local note le contenu non fiable qui afflue vers le modèle — lectures de fichiers, récupérations web, sortie d'outils — à la recherche d'instructions qui n'ont rien à y faire. Et les fichiers de règles auxquels un agent obéit sans discuter — CLAUDE.md, AGENTS.md, GROK.md — reçoivent une double passe plus sévère : une analyse déterministe pour l'Unicode invisible, les ruses de texte bidirectionnel et les méta-directives de type « ignore les instructions précédentes », plus un classifieur ModernBERT affiné pour les abus formulés calmement qu'un filtre par mots-clés laisse passer. Par profil, vous choisissez la fermeté : journaliser dans le Security Log, demander et voir le texte signalé, ou bloquer la requête avant même que le modèle ne voie le passage empoisonné. Rien ne quitte le Mac.

Le placement relève du même argument que les trois autres. Un agent qui a déjà avalé une injection ne peut pas être cru quand il la signale — la première instruction de l'injection est généralement une variante de n'en parle pas. Le détecteur ne demande pas à l'agent. Il lit le trafic de l'autre côté de la ligne, là où la persuasion de l'agent ne porte pas.

Là où la ligne ne vous sauve pas.

Une frontière est une forme précise, pas un mot magique. Quatre limites honnêtes :

Le profil est durable, donc la persistance persiste.

Un profil Bromure n'est pas un disque jetable. Une charge utile qui s'écrit dans un chemin de démarrage peut se réveiller à la prochaine session — face à un invité sans clés d'hôte et un courtier qui ne parle que des tokens éphémères, demandés, cadrés. Une présence dans une pièce sans rien dedans, mais une présence quand même.

Une écriture que vous approuvez est une écriture qui se produit.

La demande attrape l'appel dont l'agent ne vous a pas parlé. Elle ne lit pas votre diff. Approuvez un git push et Bromure le transmet — y compris, en principe, un workflow empoisonné que vous n'avez pas remarqué. Il déplace la décision vers vous et montre l'opération réelle ; la lire reste votre travail.

La carence est une fenêtre, pas un mur.

Deux jours, c'est calé sur l'écart observé entre publication et retrait. Un attaquant patient peut camper sur une version compromise au-delà de la carence et être installable le troisième jour. Cela affame les vers du jour même ; cela ne se porte pas garant d'un paquet qui a simplement vieilli. socket.dev et OSV doivent encore faire leur part.

Cadrez le courtier à dessein.

L'isolation contient l'explosion ; le cadrage décide de l'ampleur qu'elle aurait pu avoir. Un profil qui ne fait que lire un dépôt ne devrait pas détenir un token qui y écrit ; un qui ne publie jamais ne devrait détenir aucun token de publication. La ligne garde les secrets hors de la VM — quels secrets existent tout court reste votre décision.

La ligne que nous tiendrons.

Voici l'engagement. Un développeur ne devrait pas avoir à devenir un sysadmin — maintenir une liste blanche, pré-valider chaque dépendance, abandonner la vitesse qui rendait un agent digne d'être lancé — pour garder son trousseau. Un bac à sable fait de la sécurité un troc contre l'utilité, et les développeurs, sensément, continuent de choisir l'utilité. Une frontière refuse le troc : faites tout ce que vous voulez à l'intérieur, parce que l'intérieur est jetable, et les quatre choses qui comptent — vos identifiants, la portée de vos tokens, les paquets qui vous atteignent, les instructions qui atteignent votre modèle — sont décidées à une ligne avec laquelle le code à l'intérieur ne peut pas discuter.

C'est pourquoi « c'est un bac à sable » est la description que nous ne cesserons de corriger. Un bac à sable contraint l'agent. Bromure contraint la frontière, et libère l'agent. Bromure Agentic Coding est libre, open-source, et livré dès aujourd'hui.