SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-24

Cómo mantener secretos fuera de agentes de IA

Una clave de API en el entorno del agente puede filtrarse en una llamada de herramienta. Use tokens breves y limitados mediante una pasarela de credenciales.

Qué implica mantener los secretos fuera de los agentes de IA

Un agente de IA es un proceso normal de Linux que ejecuta comandos. El código que ejecuta puede leer todas las variables de entorno que contiene ese proceso. Por tanto, una clave de API en el entorno del agente es una clave que el agente puede enviar a cualquier host al que tenga acceso. Mantener los secretos fuera del agente significa proporcionarle un identificador en lugar de la clave: un token con alcance limitado y duración breve, o un marcador de posición que otro componente sustituye por el valor real en el límite de red.

Esto no trata de que un modelo se vuelva malicioso. El mecanismo es más simple. Un agente lee una página web, un README o un comentario de una incidencia que contiene instrucciones y las sigue, porque para un modelo de lenguaje no hay diferencia entre el texto que usted escribió y el texto que obtuvo de otra fuente. Eso es una inyección de instrucciones. Cuando ocurre, el alcance del daño queda limitado por un único factor: lo que el proceso puede leer. Si todavía no ha establecido un límite, ejecutar un agente de programación de forma segura en un servidor explica los niveles de aislamiento sobre los que se basa esta guía.

El modelo de amenazas en términos sencillos

Ejecute esto como el usuario con el que se ejecuta el agente.

tr '\0' '\n' < /proc/self/environ | grep -iE 'key|token|secret|password'

Cada línea que muestra equivale a una petición HTTP para el servidor de un tercero. Ahora revise qué hay en el disco cerca del agente.

grep -rIl --exclude-dir=.git -e 'API_KEY' -e 'SECRET' ~/projects
find ~ -maxdepth 3 -name '.env' -o -name 'credentials' -o -name '*.pem'

Un agente con una shell no necesita un exploit sofisticado para extraer esos datos. Cuatro vías habituales son suficientes, y las cuatro parecen trabajo normal en el registro:

  • Un curl o fetch saliente a cualquier host, con el valor en una cadena de consulta.
  • Un git commit y un git push a un repositorio en el que el agente tenga permisos de escritura.
  • Un script de instalación de paquetes, que ejecuta código arbitrario como el usuario del agente.
  • Una búsqueda DNS de un nombre de host que contenga el valor, que también funciona aunque se bloquee el tráfico HTTP saliente.

No puede resolver este problema mediante revisiones. La solución consiste en asegurarse de que no haya nada valioso al alcance.

Un secreto en el árbol de trabajo es un secreto en la ventana de contexto

Un agente lee archivos. Se leerá un archivo .env del repositorio en el que está trabajando y, una vez leído, estará en la ventana de contexto. Esto significa que aparecerá en la transcripción, en cualquier registro que conserve y en todo lo que el agente escriba después.

Antes, con la clave en el árbol en el que trabaja el agente:

cd ~/projects/billing
cat .env
# STRIPE_SECRET_KEY=sk_live_...
# DATABASE_URL=postgres://app:hunter2@db.internal:5432/billing

Después, con el archivo fuera de su alcance:

sudo install -d -m 750 -o root -g agent-review /etc/agent-review
sudo install -m 640 -o root -g agent-review ~/projects/billing/.env /etc/agent-review/billing.env
rm ~/projects/billing/.env

El usuario del agente ya no puede abrir el archivo porque el árbol de trabajo ya no lo contiene. Las reglas de denegación de la configuración del propio agente son una segunda capa, no la primera. Claude Code lee las reglas de permisos de .claude/settings.json en el proyecto:

{
  "permissions": {
    "deny": ["Read(./.env)", "Read(./secrets/**)", "Read(./**/*.pem)"]
  }
}

Esto evita que el agente abra accidentalmente un archivo mientras explora. No impide que una instrucción inyectada ejecute base64 .env, porque eso es un comando de shell y no una lectura de archivo. Que se le solicite confirmación antes de ejecutar ese comando depende del modo de permisos de la sesión. Además, el modo automático se convertirá en el modo predeterminado de Claude Code en agosto de 2026, por lo que un servidor que no está supervisando ejecutará más comandos de este tipo sin solicitar confirmación. El mismo límite se aplica a todo lo que modifica los hábitos del agente en lugar de sus permisos: una skill que obliga al agente a aplicar el cambio mínimo que funciona evita que una ejecución termine explorando archivos que no tenía motivos para abrir, pero sigue siendo una recomendación que se puede convencer al modelo de ignorar. Considere la configuración una barrera de seguridad y los permisos del sistema de archivos, la pared. La misma separación se aplica dentro de los contenedores: los archivos env y los secretos en Docker Compose cubren la versión de este problema en una capa inferior.

Asigne a cada agente su propio usuario sin privilegios

Si el agente se ejecuta con su usuario, hereda sus claves SSH, sus credenciales de nube y su historial del shell. Un usuario independiente requiere un solo comando y elimina todo eso.

sudo adduser --disabled-password --gecos "" agent-review
sudo chmod 700 /home/agent-review
sudo -u agent-review cat ~/.ssh/id_ed25519

La última línea debe fallar con cat: /home/you/.ssh/id_ed25519: Permission denied. Si muestra una clave, el directorio de inicio tiene permisos de lectura para el grupo o para otros usuarios, y chmod 700 ~ lo corrige. No añada el usuario del agente a sudo ni le conceda una regla de NOPASSWD más amplia que el único comando que realmente necesita. Usuarios con privilegios mínimos en un VPS explica los detalles de grupos y sudoers. Mantenga esta separación cuando ejecute más de una sesión en el servidor, porque una sesión de Claude Code puede enviar texto directamente a otra, y todo lo que conserve la primera sesión puede cruzar ese canal en un solo mensaje.

También conviene añadir otro límite en un VPS en la nube. El servicio de metadatos de la instancia responde en una dirección local de enlace fija y a menudo entrega credenciales de rol a cualquier proceso que las solicite.

sudo iptables -A OUTPUT -m owner --uid-owner agent-review -d 169.254.169.254 -j REJECT

Compruébelo desde el lado del agente. sudo -u agent-review curl -s --max-time 3 http://169.254.169.254/ no debe mostrar nada y debe terminar con un código distinto de cero, porque el paquete se rechaza antes de salir del servidor.

Inyecte la credencial en el perímetro

El patrón que resuelve este problema es la inyección de credenciales. El agente nunca contiene una clave real. Envía la solicitud a través de una puerta de enlace local, y la puerta de enlace sustituye un marcador de posición por el secreto real al salir. El secreto se almacena en la puerta de enlace, en otro proceso y con un usuario diferente.

OneCLI es una implementación de código abierto de este patrón, con licencia Apache-2.0, y se ejecuta como un contenedor junto al agente. En julio de 2026, el proyecto documenta esta configuración:

git clone https://github.com/onecli/onecli.git
cd onecli
docker compose -f docker/docker-compose.yml up -d --wait

El dashboard escucha en el puerto 10254 y la puerta de enlace en el puerto 10255. Almacene la credencial real una sola vez. Después, proporcione a cada agente un valor de marcador de posición en lugar de la clave, además de su propio token de acceso con alcance limitado, que envía en una cabecera Proxy-Authorization. La puerta de enlace identifica la solicitud saliente por el host y la ruta, descifra la credencial correspondiente y la sustituye. El entorno del agente no contiene nada que valga la pena robar.

La ventaja no está en el cifrado. Está en que la pregunta «qué utilizó este agente y cuándo» se convierte en una consulta de registros. Consulte un único registro de auditoría en lugar de intentar averiguar cuál de los seis entornos contenía una copia de la clave.

Entrega el secreto al proceso, no al entorno

Si ejecuta el agente con systemd, no necesita variables de entorno. LoadCredential= coloca el secreto en un directorio privado que sólo ese servicio puede leer. En el archivo de unidad se expone como %d y dentro del proceso como $CREDENTIALS_DIRECTORY. El valor nunca aparece en /proc/<pid>/environ, por lo que ps eww no puede mostrarlo. El directorio desaparece cuando se detiene el servicio.

Cifre primero la credencial para la máquina. Estos comandos proceden de la documentación de systemd y funcionan con systemd 250 o posterior, lo que incluye Ubuntu 24.04 y Debian 13:

echo -n 'sk-example-value' > /tmp/plain.txt
sudo systemd-creds encrypt --name=api_key /tmp/plain.txt /etc/credstore/api_key.cred
shred -u /tmp/plain.txt
sudo systemd-run -P --wait -p LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred \
  systemd-creds cat api_key

El último comando muestra sk-example-value. Esto confirma que el archivo cifrado se puede descifrar en este host. Después, haga referencia a él desde la unidad:

[Service]
User=agent-review
LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred
Environment=AGENT_KEY_FILE=%d/api_key
ExecStart=/usr/local/bin/agent-worker

El código del agente abre el archivo en $AGENT_KEY_FILE cuando necesita el valor. La lectura de un archivo ocurre en un momento concreto. Una variable de entorno permanece durante toda la vida del proceso y está disponible para cada proceso hijo que este genere.

Prefiera tokens de corta duración a claves de larga duración

Una clave que nunca caduca sigue siendo válida cuando vuelve a aparecer, meses después, en un registro o una transcripción. Si el servicio ofrece un token de sesión, utilice el token de sesión y establezca la duración más corta que permita el trabajo.

aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/agent-readonly \
  --role-session-name agent-review \
  --duration-seconds 900

Quince minutos es el mínimo que acepta AWS STS (security token service), y normalmente basta para una tarea de un agente. En GitHub, asigne al usuario del agente su propio gh login con un token de permisos detallados limitado al único repositorio en el que trabaja, de modo que gh auth token dentro de esa sesión devuelva algo que no pueda acceder a nada más. Limite primero por recurso y después por tiempo.

Comprueba y sigue comprobando

Conviene ejecutar tres comprobaciones después de cualquier cambio en la configuración de un agente. Ejecútalas como el usuario del agente, no como tu propio usuario.

sudo -u agent-review env | grep -iE 'key|token|secret'
sudo -u agent-review ls -la /home/you/ 2>&1 | head -3
sudo -u agent-review curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 https://api.github.com/user

La primera no debería mostrar nada. La segunda debería mostrar ls: cannot open directory '/home/you/': Permission denied. La tercera indica qué identidad presenta la ruta de red del agente. Esa es la cuestión que debe resolver el patrón de gateway: un 401 significa que el agente no transporta ninguna credencial propia de GitHub, mientras que un 200 significa que sí transporta una. Por tanto, debes saber qué token utiliza. Si ejecutas agentes sin supervisión, controlar los costes de agentes de IA en un VPS explica los límites presupuestarios que complementan estos límites de acceso.

FAQ

¿Puedo confiar en que el modelo no filtrará mis claves?

No, porque el modelo no es el atacante en este modelo de amenazas. El agente lee texto de páginas web, repositorios y gestores de incidencias, y ese texto puede contener instrucciones. El modelo no tiene una forma fiable de distinguir sus instrucciones del texto que ha obtenido. Cualquier control que dependa de que el modelo elija correctamente falla la primera vez que una instrucción inyectada resulta convincente. Por eso, el control debe estar en el sistema operativo o en la red.

¿Son realmente tan problemáticas las variables de entorno para los secretos del agente?

Lo son de una forma concreta: se heredan. Cada proceso hijo que inicia el agente recibe una copia, incluidos un script de compilación, un ejecutor de pruebas y cualquier enlace de instalación de paquetes. El mismo usuario también puede leer las variables mediante /proc/<pid>/environ. Por tanto, cualquier proceso que ejecute el agente puede leerlas sin que el agente se las transfiera. Leer un archivo en el momento de usar el secreto, mediante LoadCredential= o una pasarela, limita la exposición a ese momento.

¿Guardar los secretos en un vault resuelve el problema por sí solo?

Sólo en parte. Un vault resuelve el almacenamiento. Si aloja ese vault usted mismo, necesita su propia fase de endurecimiento, porque un servidor de Vaultwarden suele verse comprometido a través de su token de administración o su archivo de copia de seguridad, no a través de los elementos cifrados que almacena. Esto no resuelve el último paso: algo extrae el secreto del vault y se lo entrega al agente como una variable de entorno, lo que le devuelve a la situación inicial. Lo importante es quién realiza la sustitución. Si el agente obtiene el secreto, el agente tiene el secreto. Si una pasarela o el sistema de inicio realiza la sustitución fuera del proceso del agente, el agente nunca lo contiene.

¿Cómo puedo saber si un agente ya ha filtrado algo?

Por lo general, no puede saberlo a posteriori. Ese es el motivo para usar una pasarela. Sin ella, las pruebas están dispersas entre el historial del shell, la transcripción del agente y los registros de conexiones salientes que probablemente no conserva. Con una pasarela de credenciales, cada uso de una credencial queda registrado en una línea con la identidad del agente y una marca de tiempo. Si sospecha que se ha producido una filtración, rote la clave primero e investigue después. La rotación es barata y la certeza no.

¿Qué es lo mínimo que debería hacer hoy?

Mueva todos los archivos .env fuera de los directorios en los que trabajan sus agentes y cree un usuario sin privilegios para cada agente. Estos dos cambios requieren unos diez minutos y cierran la vía más habitual: que un agente lea un archivo de credenciales que no tenía ningún motivo para estar junto al código. La pasarela y los tokens de corta duración son el siguiente paso, no el primero. El mismo punto de partida se aplica a cualquier entorno de ejecución de agentes, incluido ejecutar un agente autónomo de forma segura en un VPS.