Le hook n'est jamais arrivé jusqu'au modèle
Le 31 août, Token Security a détaillé sur The Hacker News les nouveaux points d'accès de l'API Compliance d'Anthropic pour les sessions locales de Claude Code. Ce sont de vraies avancées, et l'article est précis sur l'endroit où le transcript s'arrête : les hooks qui se déclenchent avant l'exécution d'un outil, les fichiers posés sur le disque, les processus lancés hors session, tout ce qui passe par Bedrock ou Vertex. Le ver npm de la semaine dernière a vécu toute sa vie dans cet interstice. Bromure Agentic Coding pose sa sonde sur le fil entre la VM et le reste du monde : la trace couvre ce qui s'est passé, pas ce qu'on a dit au modèle.
Un transcript ne peut contenir que ce qu'on a dit au modèle. La moitié intéressante d'une session d'agent est celle que personne n'énonce à voix haute.
Pendant l'essentiel de cette année, un responsable d'ingénierie qui voulait savoir ce que Claude Code avait fabriqué sur un portable avait deux options : lire le scrollback du développeur, ou acheter un wrapper tiers. Les points d'accès de conformité d'Anthropic couvraient claude.ai et Claude Desktop, et Claude Code à peine.
Cela a changé le 11 août. Anthropic a livré trois points d'accès de l'API
Compliance pour les sessions locales : l'un liste les sessions, l'autre
récupère les métadonnées d'une session, et le troisième tire le transcript
complet depuis
GET /v1/compliance/apps/sessions/local/{session_id}/messages. Le 31 août,
Token Security a publié
un tour d'horizon de ce qu'ils offrent
sur The Hacker News.
Token Security a sponsorisé cet article, et il reste l'un des comptes rendus les plus soigneux que j'aie lus sur l'endroit où s'arrête l'horizon d'un journal.
Trois types de blocs, et ce qu'ils couvrent
Le transcript arrive sous forme de trois types de blocs. Dans les mots de
l'article : « Tout ce qui est communiqué au modèle est journalisé sous trois
types de blocs : text, tool_use et tool_result. À eux trois, ils couvrent
les prompts de l'utilisateur, les commandes bash, les lectures et les écritures,
et même les commandes MCP. »
C'est beaucoup : chaque commande shell que le modèle a choisie, chaque fichier qu'il a lu, chaque outil MCP qu'il a appelé. Si votre question est « qu'est-ce que cet agent a décidé de faire mardi », le transcript y répond, et il y répond depuis les serveurs d'Anthropic plutôt que depuis un fichier posé sur la machine que vous enquêtez.
La proposition qui fait tout le travail est la première : tout ce qui est communiqué au modèle.
L'horizon
Quatre choses se tiennent hors de cette frontière, et l'article les nomme toutes les quatre.
Les hooks. « Les hooks sont le cas le plus net : ils s'exécutent localement, entre la décision du modèle et l'exécution effective de l'outil, et peuvent empêcher un outil de s'exécuter ou un prompt d'être envoyé. » Un hook est du code posé sur le disque du développeur, qui se déclenche dans l'intervalle entre le choix d'une action par le modèle et sa réalisation. Le modèle n'en entend jamais parler, donc le transcript ne le porte jamais.
Le disque. « Ni l'un ni l'autre ne voit ce qui repose sur le disque : fichiers de configuration, skills et plugins installés avec leurs fichiers .md (sauf s'ils ont été utilisés dans une session), ou processus lancés hors session. » Une skill que vous installez sans jamais l'invoquer ne laisse aucune trace, et pas davantage un processus d'arrière-plan que l'agent a démarré il y a une heure avant de l'oublier.
Les autres fournisseurs de modèles. « Si vous faites tourner Claude Code sur un modèle qui n'est pas celui d'Anthropic, vous n'obtenez aucune couverture de l'API Compliance, car elle ne journalise que les interactions avec les modèles d'Anthropic. Les sessions tournant sur Bedrock, Foundry ou Google Cloud ne seront pas couvertes. » La couverture s'arrête aux modèles d'Anthropic, ce qui laisse dehors Codex, Gemini CLI, Grok, et ce que votre équipe installera au trimestre prochain.
Les décisions de permission. L'approbation par un développeur d'une commande dangereuse, ou un drapeau de contournement qui a fait passer tout un prompt, atterrit dans OpenTelemetry et non dans le transcript de conformité.
Tout cela est un comportement correct. Un journal ancré au modèle enregistre ce que le modèle a vu. La question pour votre prochaine revue de sécurité est de savoir si les choses que vous avez le plus besoin de voir tombent du côté du modèle de cette ligne.
Le ver de la semaine dernière vivait dans cet interstice
Il y a quatre jours, un générateur de code npm dépassant les 150 000 téléchargements hebdomadaires s'est mis à livrer un voleur d'identifiants. Nous avons décrit samedi la chaîne de publication : un inconnu a commenté une pull request, le workflow de publication du projet a lu le commentaire sans vérifier qui l'avait écrit, et dix versions signées sont parties.
Relisez ce malware avec le transcript de conformité dans l'autre main. Tracez où chaque étape apparaîtrait.
L'agent lance npm install. C'est un bloc tool_use, et le transcript le
possède. Tout ce qui suit est un processus enfant.
La première vague ne déclarait aucun script d'installation. Sa charge se logeait
dans binding.gyp, la description de build que lit node-gyp, à l'intérieur
d'un champ conditions que node-gyp évalue avec Python. Le modèle n'a jamais
eu son tour dessus et aucun appel d'outil ne le nomme : une expression Python
dans un fichier de build, tournant comme petit-enfant de l'unique commande que
le transcript a enregistrée comme parfaitement ordinaire.
Le balayage qui a suivi a parcouru plus de 150 motifs glob dans le répertoire
personnel, à la recherche de clés SSH, de fichiers .env, d'identifiants cloud
et de jetons de registre. Personne n'a posé la moindre question au modèle
là-dessus.
Puis la persistance. Dans chaque dépôt qu'il pouvait atteindre, le ver écrivait
un .claude/settings.json portant un hook SessionStart qui exécute
setup.mjs chaque fois qu'un développeur ouvre le projet dans Claude Code. Un
hook, sur le disque, se déclenchant avant que quiconque ne consulte le modèle :
deux des quatre angles morts dans un seul fichier. L'attaquant qui a choisi cet
emplacement n'avait presque certainement jamais lu le changelog de conformité
d'un éditeur.
Toute la fenêtre hostile a duré trois heures et onze minutes, et pas une seule de ses parties n'a jamais atteint un modèle.
Où Bromure pose la sonde
Bromure Agentic Coding fait tourner chaque espace de travail comme sa propre machine virtuelle sur Apple Silicon, et tout ce qui quitte cette VM traverse un proxy et un commutateur virtuel qui vivent du côté Mac de l'hyperviseur. Le commutateur détourne les flux des ports 80 et 443 de la VM vers le proxy sans aucune variable d'environnement à positionner et sans rien que l'invité puisse désactiver : la trace ne dépend donc pas de la coopération de l'agent, ni de ce que l'agent sache que le proxy est là.
Au niveau de trace Activité seule et au-dessus, chaque requête reçoit un
enregistrement de métadonnées : horodatage, hôte, port, méthode, chemin, code de
statut, latence, octets de requête mesurés avant tout échange d'identifiants,
octets de réponse, quels identifiants le proxy a substitués à la sortie, et un
avertissement si la requête portait un jeton bearer que Bromure n'a pas émis.
Cet enregistrement existe que la requête vienne de l'agent, d'un script
postinstall, d'un serveur MCP qui fait sa propre cuisine, ou d'un processus
que quelqu'un a démarré il y a trois heures avant de l'oublier.
La fenêtre Chronologie de sécurité (Window → Security Timeline…) se tient à
côté et répond à une autre question. L'Inspecteur de traces vous dit ce que
l'agent a envoyé ; la chronologie vous dit ce que les moteurs de Bromure ont
décidé. Une seule table chronologique, la plus récente en tête, en couleurs :
vert pour autorisé, rouge pour bloqué, bleu pour informatif — Courtage
d'identifiants, Pare-feu, Chaîne d'approvisionnement, Garde-fous, Injection de
prompt, Identifiant utilisé, TLS amont. Elle tient 5 000 lignes en mémoire. La
copie durable, ce sont les traces de session chiffrées sous
~/Library/Application Support/BromureAC/traces/, scellées en AES-GCM avec la
même clé de trousseau que les secrets de votre espace de travail.
La même installation, dans un espace de travail Bromure, se lit comme ceci.
Pas une seule de ces lignes n'exige que la charge soit passée par un modèle, et aucune ne peut être modifiée par du code à l'intérieur de la VM, parce que les moteurs qui les écrivent tournent sur le Mac et que l'invité n'a aucune route vers eux.
Les mêmes lignes, quel que soit l'agent que vous faites tourner
Une équipe se standardise sur Claude Code. Puis quelqu'un amène Codex pour un projet, l'équipe plateforme route un espace de travail via Bedrock pour la résidence des données, et un chercheur se met à faire tourner Grok. D'après le compte rendu de l'article lui-même, trois de ces quatre-là ne produisent rien dans l'API Compliance.
Un proxy qui lit les noms de serveur TLS voit les quatre de la même manière, et
les mêmes événements llm.request, tool.use, command.run, file.read et
file.write sortent de chacun d'eux, extraits du trafic plutôt qu'octroyés par
un éditeur. Sur un Mac enrôlé auprès d'un espace de travail bromure.io, ils sont
diffusés vers l'organisation en TLS mutuel, aux côtés de egress.firewall pour
chaque verdict du pare-feu, credential.exfiltration quand un identifiant leurre
part vers un hôte pour lequel il n'a jamais été émis, et supply_chain.fetch
pour chaque paquet que l'espace de travail a tiré. Ce dernier se déclenche même
avec toutes les couches d'application de la chaîne d'approvisionnement
désactivées, parce que Bromure sépare l'observation du blocage. Le flux ne porte
aucun prompt brut. Il répond à ce que l'agent a fait, pas à ce que le
développeur a demandé.
La phrase sur laquelle l'article se termine
La phrase la plus tranchante du texte laisse la couverture derrière elle : « à eux seuls, les journaux d'activité ne peuvent pas vous dire si l'accès d'un agent est légitime. »
Cela vaut pour n'importe quel journal, et c'est pourquoi les moteurs de Bromure écrivent eux-mêmes la chronologie au lieu de confier la tâche à un observateur séparé. Chaque ligne rouge de cette fenêtre enregistre une décision qui a déjà eu lieu. Une ligne chaîne d'approvisionnement signifie un paquet que l'agent n'a jamais reçu. Une ligne pare-feu signifie une connexion qui ne s'est jamais ouverte. La ligne Garde-fous est un push que l'hôte a refusé avec un 403, que l'agent a lu comme un échec d'API ordinaire, et la ligne de courtage d'identifiants est un leurre qui n'est jamais devenu un vrai secret, parce que le vrai n'a jamais été dans la VM.
Il vous reste à décider de la politique. Mais vous répondez à « cet accès était-il légitime » en configurant l'espace de travail, pas des semaines plus tard en lisant des lignes.
Où poser votre sonde
Si vous faites tourner des agents de code à la moindre échelle, activez l'API Compliance. Il y a quatre semaines, cette surface n'avait presque aucune visibilité, et une semaine de transcripts vous apprendra sur votre propre équipe des choses que vous ignoriez.
Puis posez la deuxième question : que faites-vous d'une machine dont le
transcript a l'air propre ? Dans un espace de travail Bromure, la réponse est
déjà à l'écran. Ouvrez Window → Trace Inspector pour les hôtes, Window →
Security Timeline pour les verdicts, ou lancez bromure-cli trace hostnames
et lisez chaque domaine que cet espace de travail a contacté depuis son
démarrage.
L'agent n'a pas besoin d'en souffler mot pour que ce soit là. Installez Bromure Agentic Coding, ouvrez la chronologie, et regardez une installation.