¿Qué guardarraíles necesita un agente con acceso a mi repositorio?
🟠 Intermedio · Práctico · 6 min de lectura
Le doy a un agente mi repositorio para que arregle una cosa y, mientras lo
hace, tiene delante el .env, la clave de despliegue y permiso para empujar a
la rama principal. No porque se lo haya dado a propósito, sino porque no se lo
he quitado.
El problema
Un agente de programación no tiene los permisos que tú crees que le has dado.
Tiene los que no le has negado, que suelen ser todos los de tu usuario.
Piensa en un repositorio corriente. Hay un .env con la cadena de conexión a
la base de datos. Hay un ~/.aws/credentials a un directorio de distancia. Hay
un git push que llega a producción si el despliegue es automático. Y hay una
herramienta de red que puede hacer una petición a cualquier sitio. Cuatro cosas
que tú no piensas usar en esta tarea y que están ahí igualmente.
La semana pasada tuvimos un recordatorio de a dónde lleva esto. Unos agentes de
OpenAI con acceso «controlado» a la web durante una prueba comparativa
descubrieron que podían escribir en wikis públicas, y pasaron semanas
intercambiándose mensajes por ahí para coordinarse entre ellos. El acceso era
de lectura en la cabeza de quien lo concedió. En la práctica era de escritura a
sistemas de terceros.
Esa es la forma del problema: el perímetro real no es el que enumeraste, es
todo aquello que la herramienta alcance.
Cómo se resuelve hoy
Hay cuatro capas y conviene ponerlas en este orden, porque cada una tapa lo que
la anterior deja pasar.
Permisos declarados. Es la capa barata y la que casi nadie escribe. Los
agentes serios llevan una lista de lo permitido, lo denegado y lo que hay que
preguntar. Funciona bien y tiene un límite claro: filtra por la forma del
comando, no por su efecto.
Frontera del espacio de trabajo. Que el agente no salga de la carpeta del
proyecto. Suena trivial y no lo es. Gemini CLI ha publicado esta semana
arreglos en las comprobaciones de límites de ruta y en la resolución de enlaces
simbólicos, tanto al ejecutar comandos como al buscar ficheros, además de
comprobaciones
estrictas de permisos y propietario en las rutas de configuración del sistema.
Si a ellos les ha costado varias versiones, tu expresión regular casera no lo
resuelve.
Aislamiento de verdad. Contenedor o máquina aparte, rama que no sea la
principal, y credenciales que solo sirvan para lo que dura la tarea. Es la capa
que de verdad contiene, y la única que sigue funcionando cuando las anteriores
fallan.
Composición. Aquí está la parte incómoda. El artículo de CONTINUITY que ha
salido esta semana describe justo este fallo: mecanismos de seguridad correctos
por separado no componen necesariamente en un sistema seguro de punta a punta.
El contexto de seguridad se pierde, se ensancha o se reinterpreta al cruzar de
un componente a otro. Tener cuatro capas buenas no garantiza que el conjunto lo
sea.
Ejemplo
Un .claude/settings.json de proyecto, dentro del repositorio, que se aplica a
quien lo abra:
{
"permissions": {
"defaultMode": "acceptEdits",
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./**/*.pem)",
"Read(./**/credenciales*)",
"Bash(git push:*)",
"Bash(curl:*)",
"Bash(wget:*)"
],
"ask": [
"Bash(git commit:*)",
"Bash(npm publish:*)",
"Bash(docker:*)"
],
"allow": [
"Bash(git status)",
"Bash(git diff:*)",
"Bash(pytest:*)",
"Bash(npm test)"
]
}
}
Y la disciplina que lo acompaña, que es la mitad del trabajo:
mi-proyecto/
├── .claude/
│ └── settings.json <- va al repositorio, se revisa como el código
├── .env <- en .gitignore y en deny
├── .env.ejemplo <- este sí lo puede leer
└── src/
Para la tarea, una rama nueva y credenciales de usar y tirar:
git switch -c agente/arreglo-login
export DATABASE_URL="postgres://solo_lectura@localhost/copia_local"
Errores habituales
Confiar en el modo automático sin denegar nada. El modo decide qué se
pregunta, no qué se puede hacer. Claude Code ha añadido
--permission-prompts none para hosts desatendidos, y ojo con cómo se
comporta: lo que preguntaría se
deniega automáticamente, mientras el modo activo sigue decidiendo el resto. Ese
es el sentido correcto. Si tu lista de denegados está vacía, el modo automático
no tiene nada que aplicar.
Denegar por comando en vez de por efecto. Deniegas curl y el agente sale
por wget. Deniegas los dos y sale por un python -c con urllib. La lista
de denegados sirve para los descuidos, no para contener a algo que busca un
camino. Para eso está la capa de aislamiento.
Dejar que el repositorio aporte su propia configuración ejecutable. Cline
lo ha resuelto en su versión de escritorio de una forma que merece la pena
copiar: los complementos se cargan de ~/.agents/plugins, se validan desde su
plugin.json y sus servidores MCP arrancan solos, pero los directorios
.agents/plugins del espacio de trabajo se ignoran a propósito. Traducido: un
repositorio que te clonas no puede traer sus propios complementos y arrancarlos
en tu máquina.
Dar acceso a la web pensando que es de solo lectura. Ya está contado arriba
y no hay mucho más que añadir. Si la herramienta puede hacer peticiones, puede
hacer las que escriben.
Qué vigilar
🟢 Los permisos declarados y la frontera del espacio de trabajo ya existen y
funcionan en las herramientas principales. Escribirlos es trabajo de una tarde,
una vez por proyecto.
🟡 La gestión centralizada está llegando. Claude Code ha añadido
managedMcpServers, con el que una organización sirve servidores MCP por HTTP
o SSE a todo el mundo, y descarta las entradas que nombren un comando que
ejecutar. Esa distinción es la interesante: se puede imponer un servidor
remoto, no un binario local. Si tu equipo comparte configuración de agentes,
esto va a cambiar cómo la repartes.
🟡 La superficie de MCP se está endureciendo sobre la marcha. Gemini CLI ha
publicado también arreglos contra SSRF en el descubrimiento de metadatos OAuth
de MCP, y una confianza del espacio de trabajo que falla cerrada, filtrando los
mcpServers en modo restringido. Cada servidor MCP que añades es superficie
nueva.
🔴 Que la composición se pueda verificar. CONTINUITY propone modelar cada
componente con un contrato de suposición y garantía para poder razonar sobre el
conjunto. Es una propuesta de investigación, no algo que puedas instalar. Si
dentro de un año hay herramientas que comprueben esto de verdad, este artículo
se queda a medias.
