Modelo de seguridad
Cómo Agora autentica a quien lo llama, aísla navegadores y apps, y contra qué no protege.
Agora controla una computadora real con sesiones de navegador logueadas. Tratá el acceso a Agora como si fuera acceso por SSH al host.
Exposición de red
- El daemon escucha en 127.0.0.1:7788 y no acepta escuchar en ninguna otra interfaz salvo que definas
AGORA_ALLOW_PUBLIC=1. No lo hagas. - Para acceder de forma remota, publicalo a través de un túnel autenticado (por ejemplo, Cloudflare Tunnel con Access o un túnel SSH). Nunca abras el puerto a internet.
- Chromium se controla con
--remote-debugging-pipe: no hay ningún puerto TCP de CDP. Los displays de X son locales al host y nunca quedan expuestos. - WebRTC necesita UDP hacia el host. Detrás de túneles HTTP, los viewers usan el transporte por WebSocket.
- El dashboard embebido se sirve con una Content Security Policy estricta (
default-src 'self').
Tokens
Toda llamada a la API necesita Authorization: Bearer <token>. Los endpoints de streaming también aceptan ?token=, porque los navegadores no pueden definir headers en pedidos de WebSocket ni de <img>.
| Token | Alcance | De dónde sale |
|---|---|---|
| Admin | Todo. | Se genera en el primer arranque en admin.token (modo 0600). agora token lo muestra. |
| Cursor | Su propio workspace y sus propios descendientes, limitado por sus permisos. | Lo devuelve una sola vez POST /v1/cursors. Agora guarda solo un hash. |
| Viewer | Ver el streaming de un workspace, con o sin input, por 24 horas como máximo. Se rechaza en cualquier otro endpoint. | POST /v1/viewer-tokens o agora open. Firmado con HMAC usando viewer.key. |
Dales a los agentes tokens de cursor, nunca el token de admin. Los permisos solo se achican a medida que bajás en el árbol: un hijo nunca puede tener un permiso que su padre no tiene, y solo los cursores con workspace pueden crear workspaces, congelar, suspender, hacer fork o tomar el control.
Aislamiento de procesos
- Cuando el daemon corre como root, las apps y los navegadores corren como el usuario sin privilegios
agora(home/var/lib/agora-apps), sin acceso a los archivos de root. - El sandbox de Chrome sigue activado.
- Cada workspace tiene sus propios procesos, su display y (por defecto) su perfil de navegador. Si hay cgroups v2 disponibles, los procesos arrancan dentro de un cgroup por workspace, que hace cumplir los límites de
memory_mbycpu_percent. - El cuerpo de los pedidos está limitado a 8 MB.
Lo que Agora no aísla
El aislamiento entre cursores del mismo workspace es lógico: dueños de pestañas, locks de superficies y alcances de tokens. Comparten un mismo display, un mismo perfil de navegador y un mismo usuario de Unix. Un cursor con permiso browser puede leer cualquier página de ese perfil.
Para agentes en los que no confiás:
- Ponelos en workspaces separados (procesos, display y perfil separados) y no les des el permiso
workspace. - Activá
sandboxen esos workspaces, así su navegador y sus apps no pueden leer el resto del host. - Usá un perfil dedicado, sin tus logins personales.
- Dejá
processydesktopdesactivados salvo que la tarea los necesite:processlanza programas como el usuarioagora.
Agora no guarda checkpoints de memoria: un workspace suspendido conserva en disco las cookies y el storage de su perfil, pero no el estado de las páginas abiertas.
Workspaces con sandbox
Poné "sandbox": true en el config de un workspace para que su Chrome y todas las apps que se lancen en él corran con una vista restringida del host:
agora api POST /v1/workspaces '{"name":"untrusted","start":true,"config":{"sandbox":true}}'
Cada proceso con sandbox arranca a través de agora sandbox-exec, que lo corre en namespaces nuevos de mount, PID, IPC y UTS:
- Todo el sistema se monta como solo lectura y sin bits setuid.
- Los directorios home,
/tmp,/run,/var/lib(donde están el estado de Agora, Docker y las bases de datos),/var/logy el directorio home de Agora quedan ocultos detrás de mounts vacíos. - Solo el directorio propio del workspace, su perfil de Chrome y su socket de X se montan con lectura y escritura.
- El workspace tiene sus propios
/tmp,/dev/shmy/procprivados. Sus apps no pueden ver, mandar señales ni hacer trace de procesos de otros workspaces. - El proceso corre como el usuario de apps sin privilegios, sin grupos suplementarios y sin capabilities. El sandbox propio de Chrome sigue funcionando adentro.
Límites:
- Solo como root. El daemon tiene que correr como root con un usuario de apps (lo que viene por defecto en
agora.service). Si no, un workspace con sandbox no arranca. - Red compartida. Los procesos con sandbox pueden llegar a servicios en
127.0.0.1, incluida la API de Agora (que igual necesita un token). No corras servicios locales sin autenticación al lado de workspaces no confiables. - Display compartido. Xvfb corre fuera del sandbox, y X11 no aísla a los clientes de un mismo display: cualquier app del workspace puede leer la pantalla y mandar input a cualquier otra ventana de ese workspace.
- Archivos del sistema legibles. Los archivos de
/etcy/usrlegibles por todos siguen siendo legibles. No guardes secretos ahí. - Mismo usuario, mismo kernel. Un exploit del kernel se escapa del sandbox. Para código hostil, usá una VM o una máquina aparte.
- Los agentes lanzados no tienen sandbox. Los agentes que arranca
cursor_spawn(claude,codex) corren como el usuario del daemon, porque necesitan sus credenciales. El sandbox cubre solo Chrome y las apps dedesktop_launch. - Sin D-Bus.
/runestá oculto, así que las apps que necesitan el bus del sistema o de sesión pierden esas funciones. - Los límites de CPU y memoria salen del
budgetdel workspace, no del sandbox.
Reportar una vulnerabilidad
Mandá un mail a security@olimpia.dev con los detalles. Por favor, no abras un issue público para reportes de seguridad.