← Volver al Blog

Dejé un agente de IA corriendo 24 horas: 3 incidentes de seguridad y los 7 permisos que hoy bloqueo antes de arrancar

Los agentes autónomos son el tema del año en las charlas técnicas de LatAm. Claude Code, Cursor, v0, Replit Agents. La promesa es la misma en todas: pásale una tarea, dejá que la máquina trabaje, volvé al rato a revisar el resultado.

Yo lo probé de verdad. Activé --dangerously-skip-permissions en Claude Code, le di una tarea real (triaje de bugs en un proyecto personal, escribir tests, abrir PRs), instalé tres Skills del marketplace público y me fui a dormir.

Veinticuatro horas después el agente había avanzado bastante. También había generado tres incidentes de seguridad, uno detrás del otro, mientras yo dormía. Ninguno se materializó por completo, pero los tres estaban a un descuido de hacerlo.

Este artículo no es sobre la factura de la API. Sobre eso ya escribí antes. Este es el material que a mí me hubiera servido leer antes de dejar el primer agente sin supervisión: los tres incidentes, cómo se mapean al OWASP LLM Top 10 2025 y al OWASP Agentic AI Top 10 2026, y la checklist de 7 permisos que hoy configuro en allow/ask/deny antes de arrancar cualquier agente nuevo.

El contexto de la computadora (importa para el resto)

No corrí el agente en un container limpio. Lo corrí en mi computadora de trabajo, que tenía:

  • credenciales de GitHub en ~/.config/gh
  • un .env de otro proyecto en el que había entrado el mismo día
  • una clave SSH que llevo dos años prometiendo mover de carpeta

El agente estaba, en teoría, limitado al directorio del proyecto. Las Skills, en teoría, hacían solo lo que declaraba el manifiesto. Confié en la configuración de la misma manera que uno confía en el folleto de seguridad del avión: lo miro para no ofender a la azafata.

Los tres incidentes en orden cronológico

Incidente 1: la Skill con un nombre casi correcto

A los cuarenta minutos, el agente instaló una Skill llamada @clawhub/docker-managr para resolver un cambio en un Dockerfile. El mes anterior yo había usado @clawhub/docker-manager. Una letra de diferencia. Es la clase de error que tu ojo corrige antes de avisarte.

La primera acción de la Skill fue leer “archivos de configuración” del proyecto. La segunda fue un POST HTTP a un servidor que no era mío. Las dos cosas estaban relacionadas, aunque solo lo entendí revisando los logs a la mañana siguiente. El manifiesto declaraba la llamada de red como “telemetría”, que es la palabra oficial para “no lo vas a mirar dos veces”.

Lo agarré porque tenía monitoreo de tráfico saliente por otros motivos. El agente no lo agarró. La Skill había sido subida al marketplace público en un episodio bautizado como ClawHavoc, en el que una auditoría de proveedores encontró que un 36% de los paquetes typosquatados llevaba prompt injection o exfiltración de datos.

Mapeo OWASP:

  • ASI04 — Supply Chain Vulnerabilities (OWASP Agentic AI Top 10 2026)
  • LLM03 — Supply Chain (OWASP LLM Top 10 2025)

Lecciones concretas:

  • Fijar versiones de Skill. Nunca latest en producción
  • Leer el manifiesto antes de instalar (a mano, sí)
  • Cualquier nombre con una letra de diferencia respecto a uno popular es sospechoso hasta demostrar lo contrario
  • Las estrellas no cuentan. Las Skills de ClawHavoc también tenían estrellas

Incidente 2: el rm -rf que casi pasa

Hora once de la ejecución. El agente decidió que unos node_modules estaban viejos y ejecutó rm -rf sobre ellos. Concretamente sobre $PROJECT_DIR/node_modules. Concretamente con la variable $PROJECT_DIR que, por un resultado de herramienta que el agente leyó mal, había quedado vacía.

rm -rf / (espacio doble, variable vacía) es el patrón de falla clásico. Anthropic incluso publicó su investigación de sandboxing tras un incidente real donde un agente limpió la carpeta home de alguien intentando quitar paquetes viejos. Era un modo de falla conocido cuando yo hice el experimento. Yo lo sabía. Confié igual.

Lo agarré porque tenía safe-rm como alias y el comando se trabó en la barra. Lo agarré yo. El agente no lo iba a agarrar. La Skill que ejecutó el comando ni siquiera validó la ruta.

Mapeo OWASP:

  • ASI02 — Tool Misuse + ASI05 — Unexpected Code Execution (OWASP Agentic AI Top 10 2026)
  • LLM08 — Excessive Agency (OWASP LLM Top 10 2025)

Lecciones concretas:

  • Sandbox de verdad, no confianza. Container Docker con --network none para tareas offline
  • Montaje explícito solo de los directorios que el agente debe tocar
  • Aliases como safe-rm en el shell del container. Es una red de seguridad, no una arquitectura
  • Anthropic recomienda permisos por defecto o modo plan para código sensible; --dangerously-skip-permissions tiene la palabra “peligroso” en el nombre por algo

Incidente 3: el .env que casi termina en GitHub

El agente decidió que un archivo de config de un proyecto vecino sería “contexto útil” para el README que estaba escribiendo. Leyó el archivo. Era un .env. El README fue commiteado a un repo público. El README tenía un bloque de código marcado como env. El bloque tenía una API key real.

Los pre-commit hooks lo pararon. Hooks que había configurado seis meses antes por otro motivo. Si esos hooks hubieran estado apagados, la clave habría vivido en GitHub unos noventa segundos antes de que el push protection la detectara. Noventa segundos más de los que quiero que cualquier clave mía esté expuesta.

El agente no exfiltró la clave a propósito. La exfiltró creyendo que era una ilustración útil, que es peor porque nadie diseñó una defensa contra “el agente quería ayudar”.

Mapeo OWASP:

  • ASI03 — Identity & Privilege Abuse + ASI04 — Supply Chain (OWASP Agentic AI Top 10 2026)
  • LLM06 — Sensitive Information Disclosure (OWASP LLM Top 10 2025)

Lecciones concretas:

  • Archivo de ignore explícito (.claudeignore, .agentignore, según tu framework)
  • Se pueden incluir rutas fuera de la raíz del proyecto (~/.ssh/, ~/.config/gh/)
  • Pre-commit hooks con git-secrets o trufflehog como segunda línea de defensa
  • Nunca como única línea de defensa. Tarde o temprano el agente va a tocar algo que no debería

La checklist de 7 permisos que hoy bloqueo antes de arrancar

Después de esa noche cambié el flujo. Antes de dejar cualquier agente sin supervisión, paso por esta lista. Está pensada para el sistema de allow/ask/deny de Claude Code, pero se traduce a Cursor Rules, MCP allowlist y patrones equivalentes.

Checklist de 7 permisos a bloquear antes de arrancar un agente autónomo, con el mapeo al OWASP LLM Top 10 y al Agentic AI Top 10

Permiso 1 — Secretos y archivos sensibles → deny. Regla explícita para .env, *.pem, *.key, credentials.json, secrets/, ~/.ssh/*, ~/.config/gh/*. En Claude Code se escribe como Read(**/.env) y Read(~/.ssh/**) en permissions.deny. Bloqueo de lectura, no solo de escritura.

Permiso 2 — Comandos destructivos → deny. Bash(rm -rf *), Bash(sudo *), Bash(chmod 777 *), Bash(dd *). No confío en el agente para saber cuándo una ruta absoluta es peligrosa. Prefiero que la política lo diga antes.

Permiso 3 — Red hacia hosts arbitrarios → ask. Bash(curl *) y Bash(wget *) no se auto-aprueban. Anthropic ya los deja así por defecto (Claude Code docs), pero si tenés allow amplio, revisá que no cayera dentro. Cada llamada de red saliente pasa por aprobación manual o allowlist de hosts específicos.

Permiso 4 — Git push a ramas protegidas → deny. Bash(git push origin main), Bash(git push --force *). El agente puede armar el PR; el push a main lo hace un humano. Esto también protege contra ASI08 (Cascading Failures) cuando el agente se equivoca dos veces seguidas y quiere corregir empujando.

Permiso 5 — Instalación de Skills/MCP nuevas → ask. No auto-instalar. Cada nueva Skill o MCP server requiere aprobación explícita, con lectura del manifiesto y verificación de que las llamadas de red declaradas tienen razón de estar. Este es el escudo específico contra ASI04.

Permiso 6 — Acceso a archivos fuera del proyecto → deny. Claude Code por defecto solo escribe en el directorio donde arrancó, pero lee fuera. Bloqueo lectura explícita a rutas de otros proyectos con Read(../otro-proyecto/**) en deny. El incidente 3 empieza aquí.

Permiso 7 — Ejecución de scripts descargados → deny. Bash(sh <(curl *)), Bash(bash <(wget *)), Bash(*.sh) sobre archivos que el mismo agente descargó en la sesión. Es el patrón “curl | bash” transformado en riesgo agentic.

Cómo se ve la configuración concreta

Un fragmento de .claude/settings.json con estas reglas aplicadas:

{
  "permissions": {
    "deny": [
      "Read(**/.env)",
      "Read(**/.env.*)",
      "Read(**/*.pem)",
      "Read(**/*.key)",
      "Read(~/.ssh/**)",
      "Read(~/.config/gh/**)",
      "Bash(rm -rf *)",
      "Bash(sudo *)",
      "Bash(chmod 777 *)",
      "Bash(git push --force *)",
      "Bash(git push origin main)"
    ],
    "ask": [
      "Bash(curl *)",
      "Bash(wget *)",
      "Bash(npm install *)",
      "Bash(pip install *)"
    ],
    "allow": [
      "Bash(ls *)",
      "Bash(cat *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Read(./**)"
    ]
  }
}

Este archivo se versiona con el proyecto y se comparte con el equipo. Si alguien del equipo lo cambia sin revisar, un hook ConfigChange puede alertarlo o bloquearlo.

Por qué esto importa para equipos que están adoptando ahora

Dos motivos que veo en el terreno.

El OWASP publicó el Agentic AI Top 10 en diciembre de 2025. Eso significa que hay un marco explícito para conversar con seguridad, con auditoría o con el cliente. Cuando alguien te pregunte “¿cómo lo controlan?”, el mapa ASI01–ASI10 te da un lenguaje compartido. Antes de eso había una charla técnica; ahora hay una checklist auditada.

El daño de un vector destructivo es asimétrico. El costo de la API está acotado. El costo de una API key filtrada, un rm -rf que borra código sin commitear, o una Skill exfiltrando datos de cliente no lo está. La checklist es tediosa cinco minutos; la remediación de un incidente real es tediosa varias semanas. Prefiero los cinco minutos.

El experimento me dio la checklist, no la capacidad

Cuando arranqué las 24 horas esperaba aprender qué podía hacer el agente. Salí con una lista de qué no dejarle hacer. La segunda lista me resultó más útil que la primera. La capacidad la mejora Anthropic cada dos meses; los permisos los tengo que mantener yo.

Si estás por dejar a tu primer agente correr sin supervisión: pasá primero por los siete permisos. Diez minutos de configuración te ahorran la reunión post-incidente en la que hay que explicar cómo un rm -rf salió de un LLM y llegó a producción.


ken imoto · WebRTC & Voice AI engineer · kenimoto.dev