Laissez une extension de navigateur prendre en main en toute sécurité les outils browser de Hermes : le guide du contrôleur authentifié


Vous avez une page ouverte dans votre navigateur et vous voulez que Hermes la manipule pour vous — remplir le formulaire, tourner les pages, capturer des preuves en captures d’écran. L’ancienne réponse consistait à le pointer vers un « browser backend » : un navigateur cloud, ou du CDP local. Mais l’onglet que vous utilisez réellement et le « browser backend » que Hermes lance sont deux choses différentes. La forme idéale : l’extension de navigateur que vous avez installée devient le canal de contrôle, si bien que l’agent pilote la page même qui est devant vous. Cela soulève cependant une question de sécurité tranchée — pourquoi faire confiance à une extension, et où se situe exactement la frontière de ce qu’elle peut faire ?

La réponse de Hermes est une voie authentifiée appelée browser extension controller : une extension s’enregistre comme contrôleur exact des outils browser_* d’une session via un ticket WebSocket à usage unique, et les capacités sont filtrées par une allowlist stricte — pas de CDP brut, pas d’évaluation de script arbitraire, pas d’accès console. Une fois liée, elle se ferme en échec : un contrôleur manquant, ambigu, déconnecté ou incompétent fait échouer l’appel au lieu de basculer silencieusement vers un autre browser backend. La fonctionnalité arrive avec la PR #91535 (un sauvetage de la #85351 avec les commits de l’auteur d’origine cherry-pickés et préservés), fusionnée dans le main upstream — elle n’est encore dans aucun tag de release.

Pourquoi une voie « contrôleur » ?

Les outils navigateur de Hermes (browser_navigate, browser_click, browser_snapshot, …) reposent sur plusieurs backends : Browserbase cloud, Browser Use, CDP Chromium local, Camofox… — tous sont « un navigateur que Hermes démarre lui-même ». Mais le navigateur que vous utilisez est d’une autre espèce : non lancé par Hermes, c’est l’instance que vous pilotez chaque jour.

Le contrôleur d’extension comble exactement cette lacune : l’extension détient votre vrai onglet de navigateur, Hermes envoie les commandes browser_* sur un canal WebSocket authentifié, et l’extension les exécute dans la vraie page puis rend compte. Commandes, capacités et propriété sont toutes contraintes par une allowlist côté serveur et des tickets à usage unique.

Activer la configuration

La fonctionnalité est désactivée par défaut et doit être activée explicitement — et le chemin d’API local exige en outre la clé bearer du serveur d’API :

browser:
  extension_control:
    enabled: true

Un contrôleur ne peut s’enregistrer que pour une session serveur existante ; le principal du contrôleur est dérivé de l’état authentifié du serveur, et un principal_id fourni par le client est ignoré — l’identité n’est pas quelque chose que le client peut déclarer.

L’allowlist de capacités : 11 éléments, pas de CDP brut

GET /v1/capabilities expose si la fonctionnalité est activée, la version du protocole, les noms des transports et l’allowlist exacte des capacités :

controller.noop
browser_back
browser_click
browser_navigate
browser_press
browser_screenshot
browser_scroll
browser_snapshot
browser_tab_activate
browser_tabs
browser_type

Les capacités demandées hors de cette liste sont filtrées. Notez l’arbitrage délibéré : le CDP brut, l’évaluation de script arbitraire, l’accès console, les téléversements, l’extraction d’images et la vision ne font pas partie du protocole du contrôleur — l’extension peut aider l’agent à cliquer, taper, défiler et capturer des écrans, mais elle ne peut pas exécuter de JavaScript arbitraire dans la page. C’est une frontière de sécurité volontairement étroite : capable, mais pas effrayante.

Enregistrement et connexion : ticket à usage unique, TTL de 30 secondes

Le flux comporte trois étapes (enregistrement via l’API locale) :

  1. Envoyez un POST /v1/browser-control/register authentifié avec protocol_version, session_id, controller_id, browser_profile_id et les capabilities demandées ;
  2. Hermes renvoie un ticket à usage unique (TTL de 30 secondes) avec la portée du contrôleur filtrée et liée au serveur ;
  3. Ouvrez GET /v1/browser-control/ws avec les deux sous-protocoles WebSocket : hermes-browser-control-v1 et hermes-browser-control-ticket.<ticket>.

Le ticket n’est jamais accepté dans la chaîne de requête ; les tickets inconnus, expirés, réutilisés ou malformés échouent avant l’upgrade WebSocket. Une fois connecté, Hermes envoie des trames browser.controller.command (avec command_id, action, arguments immuables et le tool_call_id d’origine), et le contrôleur répond par browser.controller.result (même command_id, booléen ok exact, et soit result soit error). Les annulations et les délais émettent browser.controller.cancel ; les résultats tardifs sont ignorés.

Fermeture en échec : pas de bascule silencieuse de navigateur une fois lié

C’est la partie qu’il faut le plus souligner :

  • Sans identité de contrôleur liée, ou lorsque la fonctionnalité est désactivée → Hermes conserve le browser backend existant ;
  • Une fois que la gateway a lié un principal de contrôleur et une famille de transport à la requête, cette voie d’extension fait autorité : les contrôleurs manquants, ambigus, déconnectés ou incompétents échouent en se fermant au lieu de basculer silencieusement vers un autre navigateur local/cloud ;
  • Après la sélection d’un contrôleur exact, son résultat ou son erreur fait autorité, et Hermes ne réessaie jamais la même action via un autre backend.

Autrement dit : une session « contrôle cet onglet » ne sautera jamais en douce vers un navigateur cloud dans votre dos. Une perte de socket inattendue est traitée comme une déconnexion récupérable (le travail en cours survit jusqu’à l’échéance de chaque commande) ; un browser.controller.detach explicite sur le transport authentifié est la séparation dure, annulant immédiatement le travail en attente. Un identifiant de contrôleur différent ou un autre profile navigateur dans la même voie de session authentifiée est un remplacement dur : l’ancien travail en attente est annulé avant que le successeur ne devienne routable.

Statut actuel et comment l’essayer

  • Code : feat(browser): authenticated extension controller (salvage #85351), PR #91535, fusionnée dans main le 2026-08-21.
  • Statut de release : dans aucun tag de release pour l’instant — le tag v2026.8.19 de v0.20.5 a été coupé avant cette fusion. Elle vit actuellement sur main uniquement ; une fois qu’elle sortira avec une future release, hermes update l’apportera.
  • Flux compagnon : le flux d’appairage d’extension navigateur en boucle locale (PR #88203, la moitié gateway du « un clic d’approbation donne un token à portée limitée ») est toujours ouvert — l’expérience « installez et cliquez pour approuver » n’est donc pas encore fusionnée ; pour l’instant, vous passez par l’authentification du serveur d’API + le flux d’enregistrement vous-même.

Pour l’essayer : procurez-vous un build de main qui inclut la PR, activez browser.extension_control.enabled, configurez la clé bearer du serveur d’API, et utilisez le client WebSocket de votre choix pour enregistrer un contrôleur de test selon les trois étapes ci-dessus, en commençant par controller.noop pour valider le canal. Pour en savoir plus sur la sélection et les modes des backends navigateur, consultez notre guide du mode Browser Use CLI 3.0 et le guide du navigateur de lecture/aperçu du desktop.

La vraie valeur de cette fonctionnalité n’est pas « une manière de plus de se connecter » — c’est que le navigateur que vous utilisez réellement devient, pour la première fois, un environnement d’exécution sûrement contrôlable pour l’agent : l’allowlist réduit la surface d’attaque, le ticket à usage unique bloque la relecture, et la fermeture en échec rend impossible la dérive silencieuse de backend. Quand le flux d’appairage arrivera, installez l’extension, cliquez sur approuver, et Hermes travaille dans la page devant vous.