# Seguridad — Protecciones contra prompt injection y abuso de tools Este documento describe las capas de defensa implementadas para proteger los agentes Matrix contra ataques de prompt injection y abuso de herramientas. ## Capas de defensa La estrategia es **defensa en profundidad**: multiples capas independientes, ninguna es la unica barrera. ``` Mensaje del usuario | v 1. Input sanitization (pkg/sanitize/) — detecta patrones de injection | v 2. System prompt hardening — instrucciones anti-manipulation al LLM | v 3. Tool validation (deny-by-default) — cada tool valida sus inputs | v 4. Rate limiting (tools/registry.go) — limite de tool calls por room | v 5. RBAC (pkg/acl/) — control de acceso por usuario/rol ``` ## 1. Sanitizacion de input (`pkg/sanitize/`) Funciones puras que detectan patrones de prompt injection en mensajes entrantes. **Configuracion:** ```yaml security: sanitize: enabled: true mode: warn # warn | strip | reject min_severity: medium # low | medium | high disabled_patterns: [] # nombres de patrones a ignorar ``` **Modos:** - `warn`: loguea warnings pero no modifica el mensaje (default) - `strip`: elimina las secciones sospechosas del mensaje - `reject`: rechaza el mensaje completamente con respuesta de error **Patrones detectados:** - Delimitadores de sistema: `<|system|>`, `<|assistant|>`, `[INST]` - Frases de override: "ignore previous instructions", "you are now", etc. - Intentos de exfiltracion: "repeat your instructions", "show me your prompt" Los patrones estan en `pkg/sanitize/patterns.go`. Son extensibles. ## 2. Hardening de system prompts Todos los system prompts deben incluir una seccion de seguridad obligatoria. Template en `.claude/templates/security-prompt.md`. Las instrucciones cubren: - Rechazo de acciones fuera del rol - Proteccion del system prompt (no revelar) - Rechazo de comandos destructivos - Validacion de coherencia contextual - Resistencia a redefinicion de identidad ## 3. Validacion en tools (deny-by-default) Cada tool que hace I/O valida sus inputs de forma independiente. ### `tools/file/` — read_file - **Deny-by-default**: si `AllowedPaths` esta vacio, todo denegado - **Path traversal**: resuelve symlinks con `filepath.EvalSymlinks`, valida que el path este dentro de los permitidos - **Prefix confusion**: usa separador de directorio para evitar que `/allowed/path` matchee `/allowed/pathevil` ### `tools/ssh/` — ssh_command - **AllowedCommands**: allowlist de prefijos de comandos. Si esta definida, solo los comandos que matcheen se ejecutan - **ForbiddenCommands**: blocklist como segunda capa - **Validacion de sintaxis**: detecta pipes `|`, subshells `$()`, redirects `>`, chains `&&`/`||`/`;` - **AllowedTargets**: solo los hosts configurados ### `tools/http/` — http_get, http_post - **AllowedDomains**: solo los dominios configurados - **SSRF protection**: resuelve DNS y bloquea IPs privadas (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), link-local (169.254.0.0/16) y metadata (169.254.169.254) ### `tools/matrix/` — matrix_send - **AllowedRooms**: si esta configurado, solo permite enviar a rooms especificos ## 4. Rate limiting Limite de tool calls por room por minuto. Previene abuso repetitivo. **Configuracion:** ```yaml security: tool_rate_limit: enabled: true max_calls_per_min: 10 # default 10 cleanup_interval_s: 60 # limpieza de entries expiradas ``` Implementado en `tools/ratelimit.go` como sliding window per room. El registry verifica antes de ejecutar cada tool. ## 5. Aislamiento de filesystem `storage.base_path` permite mover datos de runtime fuera del arbol del proyecto: ```yaml storage: base_path: /var/lib/agents/mi-bot # o via $AGENTS_DATA_DIR ``` Prioridad: config `base_path` > `$AGENTS_DATA_DIR/` > `agents//data/` (default). Esto previene que tools como `read_file` accedan accidentalmente a codigo fuente, `.env`, o configs del proyecto. ## 6. Aislamiento de claude -p (provider claude-code) Cuando un agente usa el provider `claude-code`, el subproceso `claude -p` se ejecuta en un directorio de trabajo aislado, no en la raiz del repositorio. **Configuracion:** ```yaml llm: primary: claude_code: working_dir: "/tmp/claude-agents/mi-bot" # directorio aislado ``` **Comportamiento:** - Si `working_dir` esta configurado: se crea el directorio automaticamente con `MkdirAll` y se usa como CWD del subproceso - Si `working_dir` esta vacio: se crea un directorio temporal (`os.MkdirTemp`) y se loguea un WARN para que el operador lo note - **Nunca** se hereda el CWD del launcher (raiz del repo) Esto evita que el subproceso `claude -p` tenga acceso de lectura/escritura al codigo fuente del proyecto, incluso con `permission_mode: bypassPermissions`. Implementado en `shell/llm/claudecode.go` → `resolveWorkDir()`. ## 7. Sistema de grupos centralizados (`security/`) Control de acceso centralizado: quien puede hablar con que agentes, y que puede hacer. Reemplaza los campos per-agente `security.roles` y `matrix.filters.allowed_users` (ahora deprecados). ### Estructura de archivos ``` security/ user-groups.yaml # grupos de usuarios Matrix agent-groups.yaml # grupos de agentes permissions.yaml # politicas: que grupo de usuarios tiene que acciones en que agentes ``` ### user-groups.yaml ```yaml groups: admins: members: ["@admin:matrix-af2f3d.organic-machine.com"] developers: members: ["@dev1:homeserver.com", "@dev2:homeserver.com"] everyone: members: ["*"] # wildcard: todos los usuarios ``` ### agent-groups.yaml ```yaml groups: all: agents: ["*"] # wildcard: todos los agentes production: agents: ["assistant-bot", "asistente-2"] ``` ### permissions.yaml ```yaml policies: - agent_group: all # aplica a todos los agentes permissions: - user_group: admins actions: ["*"] # admins pueden hacer todo - user_group: everyone actions: ["ask"] # todos pueden chatear - agent_group: production # solo agentes de produccion permissions: - user_group: developers actions: ["ask", "command:deploy", "tool:ssh_command"] ``` ### Acciones disponibles | Accion | Descripcion | |--------|-------------| | `*` | Todo permitido | | `ask` | Puede chatear con el agente (mensajes normales) | | `command:` | Puede ejecutar el comando `!` | | `tool:` | El LLM puede llamar la tool `` para este usuario | ### Resolucion de ACL Al arrancar, el launcher: 1. Carga todos los YAMLs con `shellsecurity.Load("security/")` 2. Para cada agente, llama `pksecurity.ResolveACL(agentID, policy)` 3. Inyecta la `acl.ACL` resultante en `agents.New()` **Comportamiento cuando la politica esta vacia**: si `security/` no existe o no hay politicas que apliquen al agente, la ACL esta vacia y el acceso es abierto (sin restricciones). Preferible a denegar todo por defecto en produccion. ### Campos deprecados Los siguientes campos en `config.yaml` del agente estan deprecated y no tienen efecto desde la activacion del sistema centralizado: - `security.roles` — reemplazado por `security/permissions.yaml` - `matrix.filters.allowed_users` — reemplazado por `security/user-groups.yaml` Los campos siguen en el schema para compatibilidad con configs existentes y se eliminarán en un issue futuro. ## Activacion Para activar todas las protecciones, añadir al `config.yaml` del agente: ```yaml security: sanitize: enabled: true mode: warn tool_rate_limit: enabled: true max_calls_per_min: 10 ``` Y asegurarse de que: - Las tools tienen allowlists configuradas (no vacias si se quieren usar) - El system prompt incluye la seccion de seguridad - `storage.base_path` apunta fuera del proyecto en produccion - `claude_code.working_dir` apunta fuera del repo si se usa el provider claude-code