Deja que una extensión de navegador asuma con seguridad el control de las herramientas de navegador de Hermes: la guía del controller autenticado

Tienes una página abierta en tu navegador y quieres que Hermes trabaje por ti — que rellene el formulario, que pase las páginas, que capture la evidencia en pantalla. La respuesta de siempre era apuntarlo a un «backend de navegador»: un navegador en la nube o un CDP local. Pero la pestaña que realmente estás usando y el «backend de navegador» que lanza Hermes son dos cosas distintas. La forma ideal es: la extensión de navegador que instalaste se convierte en el canal de control, de modo que el agente maneje exactamente la página que tienes delante. Eso plantea una pregunta de seguridad contundente: ¿por qué debería confiarse en una extensión y dónde está exactamente el límite de lo que puede hacer?
La respuesta de Hermes es una vía autenticada llamada browser extension controller: una extensión se registra como el controller exacto de las herramientas browser_* de una sesión mediante un ticket WebSocket de un solo uso, y las capacidades se filtran a través de una allowlist estricta — sin CDP crudo, sin evaluación arbitraria de scripts, sin acceso a la consola. Una vez vinculado, falla en modo cerrado (fail-closed): un controller ausente, ambiguo, desconectado o sin capacidad hace fallar la llamada en lugar de cambiar silenciosamente a otro backend de navegador. La función aterriza en el PR #91535 (un rescate de #85351 con los commits del autor original seleccionados y preservados), fusionado en main upstream — todavía no está en ninguna tag de release.
¿Por qué una vía de «controller»?
Las herramientas de navegador de Hermes (browser_navigate, browser_click, browser_snapshot, …) se apoyan en varios backends: Browserbase cloud, Browser Use, CDP de Chromium local, Camofox… — todos son «un navegador que Hermes arranca por sí mismo». Pero el navegador que tú usas es otra especie: no lo lanza Hermes, es la instancia que manejas a diario.
El extension controller cubre exactamente ese hueco: la extensión tiene tu pestaña real del navegador, Hermes envía comandos browser_* por un canal WebSocket autenticado y la extensión los ejecuta en la página real y devuelve el resultado. Comandos, capacidades y titularidad están limitados por una allowlist del lado del servidor y tickets de un solo uso.
Activando la configuración
La función está desactivada por defecto y hay que activarla explícitamente — y la vía de API local requiere además la bearer key del API server:
browser:
extension_control:
enabled: true
Un controller solo puede registrarse para una sesión de servidor existente; el principal del controller se deriva del estado autenticado del servidor, y un principal_id suministrado por el cliente se ignora — la identidad no es algo que el cliente pueda declarar.
La allowlist de capacidades: 11 elementos, sin CDP desnudo
GET /v1/capabilities expone si la función está activada, la versión del protocolo, los nombres de transporte y la allowlist exacta de capacidades:
controller.noop
browser_back
browser_click
browser_navigate
browser_press
browser_screenshot
browser_scroll
browser_snapshot
browser_tab_activate
browser_tabs
browser_type
Las capacidades solicitadas que estén fuera de esa lista se filtran. Fíjate en la decisión deliberada: el CDP crudo, la evaluación arbitraria de scripts, el acceso a la consola, las subidas, la extracción de imágenes y la visión no forman parte del protocolo del controller — la extensión puede ayudar al agente a hacer clic, escribir, desplazarse y capturar pantallas, pero no puede ejecutar JavaScript arbitrario en la página. Es una frontera de seguridad deliberadamente estrecha: capaz, pero no aterradora.
Registro y conexión: ticket de un solo uso, TTL de 30 segundos
El flujo tiene tres pasos (registro en la API local):
- Envía un
POST /v1/browser-control/registerautenticado conprotocol_version,session_id,controller_id,browser_profile_idy lascapabilitiessolicitadas; - Hermes devuelve un ticket de un solo uso (TTL de 30 segundos) con el alcance del controller filtrado y vinculado al servidor;
- Abre
GET /v1/browser-control/wscon ambos subprotocolos WebSocket:hermes-browser-control-v1yhermes-browser-control-ticket.<ticket>.
El ticket nunca se acepta en la query string; los tickets desconocidos, caducados, reutilizados o malformados fallan antes del upgrade de WebSocket. Una vez conectado, Hermes envía tramas browser.controller.command (con command_id, action, arguments inmutables y el tool_call_id de origen), y el controller responde con browser.controller.result (mismo command_id, booleano exacto ok, y result o error). Las cancelaciones y los timeouts emiten browser.controller.cancel; los resultados tardíos se ignoran.
Fail-closed: sin cambios silenciosos de navegador una vez vinculado
Esta es la parte que más merece la pena destacar:
- Sin identidad de controller vinculada, o con la función desactivada → Hermes conserva el backend de navegador existente;
- Una vez que el gateway vincula un principal de controller y una familia de transporte a la petición, esa vía de extensión es la autoritativa: los controllers ausentes, ambiguos, desconectados o sin capacidad fallan en modo cerrado (fail closed) en lugar de cambiar silenciosamente a otro navegador local o en la nube;
- Tras seleccionar un controller exacto, su resultado o error es autoritativo, y Hermes nunca reintenta la misma acción a través de otro backend.
En otras palabras: una sesión de «controla esta pestaña» nunca saltará en silencio a un navegador en la nube a tus espaldas. Una pérdida inesperada del socket se trata como una desconexión recuperable (el trabajo en curso sobrevive hasta el plazo de cada comando); un browser.controller.detach explícito en el transporte autenticado es la separación dura, que cancela de inmediato el trabajo pendiente. Un id de controller distinto o un browser profile distinto en la misma vía de sesión autenticada es un reemplazo duro: el trabajo pendiente anterior se cancela antes de que el sucesor sea enrutable.
Estado actual y cómo probarlo
- Código:
feat(browser): authenticated extension controller (salvage #85351), PR #91535, fusionado enmainel 2026-08-21. - Estado de release: todavía no está en ninguna tag de release — la tag v2026.8.19 de v0.20.5 se cortó antes de esta fusión. Actualmente vive solo en
main; cuando salga con una release futura,hermes updatelo traerá. - Flujo complementario: el flujo de pairing de la extensión de navegador por loopback (PR #88203, la mitad del gateway del «un clic de aprobación consigue un token con alcance») sigue abierto — así que la experiencia de instalar-y-clic-para-aprobar todavía no está fusionada; por ahora pasas por la autenticación del API server + el flujo de registro por tu cuenta.
Para probarlo: consigue una build de main que incluya el PR, activa browser.extension_control.enabled, configura la bearer key del API server y usa el cliente WebSocket que prefieras para registrar un controller de prueba siguiendo los tres pasos anteriores, empezando por controller.noop para validar el canal. Para más información sobre la selección y los modos de backend de navegador, consulta nuestra guía de modos de Browser Use CLI 3.0 y la guía de navegador de lectura y vista previa en el escritorio.
El valor real de esta función no es «una forma más de conectarse» — es que el navegador que realmente usas se convierte por primera vez en un entorno de ejecución controlable con seguridad para el agente: la allowlist reduce la superficie de ataque, el ticket de un solo uso bloquea la reutilización y el fail-closed hace imposible la deriva silenciosa de backend. Cuando llegue el flujo de pairing, instala la extensión, haz clic en aprobar y Hermes trabajará en la página que tienes delante.