Guía9 min

Secretos para agentes de IA: env, GitHub Actions y lo que nunca va al prompt

Resumen

Un agente que lee .env y lo pega en el chat ya filtró la clave. Esta guía separa tres capas: archivos locales que no se commitean, secrets cifrados de GitHub Actions y el contrato de no inyectar secretos en el contexto del modelo. Checklist corto, sin un vault extra.

GitHub
Tres capas: archivo local, secreto de CI y un modelo que no recibe la clave

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

Un coding agent con shell y read_file ve tu disco. Si .env está en el worktree, lo puede citar, resumir o mandar a un log. El fallo no es “el modelo es malo”: es que el secreto entró al contexto. GitHub cifra secrets de Actions y los enmascara en logs; el chat del agente no.

Esta guía no reemplaza sandboxing ni prompt injection. Cubre un solo hábito: el modelo nunca ve sk- / whsec_ / tokens.

Tres capas, una regla

CapaDónde viveEl agente ¿lo lee?CI ¿lo usa?
.env localDisco, gitignoredSí, si el path está permitidoNo
Secret de ActionsSettings → Secrets (repo / org / environment)NoSí, como env del job
Prompt / memoria / RAGTokens del modeloEs el leakN/A

Regla: tools de lectura no incluyen .env, .env.*, credentials.json, *.pem. Si tu harness no tiene deny-list, el agente es un cat con opinión.

Capas de secretos: disco, CI y modelo

Local: gitignore es el control

# .gitignore
.env
.env.*
!.env.example

.env.example lista nombres, nunca valores. El agente puede rellenar el example; tú pegas valores fuera del chat (o printenv en tu terminal, no en la del agente).

Si ya commiteaste un secreto: rótalo. Quitar el commit no basta; asume filtrado. GitHub secret scanning avisa en muchos formatos; no esperes al aviso.

Worktrees duplican el disco: cada path necesita su .env o ninguno. No copies secretos “por si el agente los necesita”. El curso instalar un agente corre local; las claves de APIs van en el entorno del proceso, no en CLAUDE.md.

GitHub Actions: el sitio correcto

La documentación de GitHub (“Using secrets in GitHub Actions”) cubre:

  • Secrets a nivel repo, org y environment.
  • Referencia en YAML: ${{ secrets.NAME }} — el runner inyecta el valor; no lo pongas en echo “para debug”. GitHub intenta enmascarar coincidencias en logs; no es un contrato criptográfico contra un base64 creativo.
  • PRs desde forks no reciben secrets del repo por default (evitar que un PR malicioso exfiltre). Un agente que abre PRs desde tu fork personal en el mismo repo corre con secrets si el workflow está en pull_request del repo origen: trata esos workflows como código de producción.
  • GITHUB_TOKEN es automático y acotado. No lo sustituyas por un PAT de admin “porque el agente pushea”.
jobs:
  test:
    environment: preview
    env:
      API_KEY: ${{ secrets.API_KEY }}
    steps:
      - run: pnpm test

El job ve API_KEY. El markdown del PR no. Si el agente escribe el workflow, revisa que no haga echo $API_KEY ni suba artifacts con .env.

CI inyecta el secreto al job, no al chat

El prompt es un log público

Cualquier tool call, trace o “pega el error completo” puede reimprimir headers Authorization. Defensas mínimas:

  1. Deny-list de paths en el sandbox (**/.env, **/id_rsa).
  2. Redact en logs: regex sk-[a-zA-Z0-9]+, ghp_, whsec_.
  3. Memoria / RAG sin archivos de credenciales.
  4. Si el agente debe llamar una API, la tool usa process.env en tu código, no un string que el modelo inventó.

OIDC (la sección de seguridad de Actions) evita un secreto estático hacia AWS/GCP: el job pide un token de corta vida. Si el agente “necesita un AWS key en el repo”, esa es la señal de que el diseño está mal: el rol lo asume el runner, no el chat.

Checklist

  • .env gitignored; git check-ignore -v .env dice que sí.
  • Ningún secreto en AGENTS.md / CLAUDE.md / issues.
  • Actions: secrets en Settings, no en YAML.
  • Workflows de fork sin secrets de producción.
  • Rotación lista: un comando, no un ritual.
  • El agente no tiene cat irrestricto sobre $HOME.

Si el harness (Claude Code, Codex, Cursor) pide “full disk”, bájalo: allowlist del repo, deny .env. Un agente de soporte o de ventas no necesita ~/.ssh. El leak típico no es un atacante sofisticado: es un debug: true que imprime el request.

FAQ

¿Un vault (1Password, Doppler)? Cuando hay más de un humano o más de un entorno. Hasta entonces, .env + Actions llega.

¿El enmascarado de GitHub es suficiente? No contra un dump ofuscado. Evita imprimir.

¿Puedo dejar la key en un comentario “temporal”? No. El índice de Git y el contexto del agente duran más que tu “temporal”.

Verificado 2026-09-03 contra GitHub Docs — Using secrets in GitHub Actions. Si un proveedor de modelos pide “pega tu API key en el system prompt para tools”, ignóralo: la tool corre en tu proceso y lee el entorno. El modelo solo ve el nombre de la tool y el schema, no el secreto.