DEV Community

Juan Torchia
Juan Torchia Subscriber

Posted on Originally published at juanchi.dev

Claude API key seguridad: por qué el .env no es opcional

Abrís un archivo route.ts en un proyecto Next.js, necesitás probar rápido una llamada a la API de Claude, y la tentación es escribir directamente const apiKey = "sk-ant-api03-..." arriba de todo. "Después la saco", pensás. El problema es que "después" casi nunca llega antes del primer git commit, y una vez que esa key entra al historial, sacarla del archivo actual no la sacó de ningún lado.

Mi tesis es simple y no tiene matices: nunca hardcodees una API key, ni "solo para probar". Los logs y el historial de git no perdonan. No es una regla de estilo, es una decisión que tiene consecuencias medibles en el momento exacto en que alguien clona ese repo o cuando un log de error termina en una herramienta de monitoreo que no controlás.

El problema real: dónde termina esa key que "es solo para probar"

Cuando trabajás con Cline conectado a OpenRouter o directo a la API de Anthropic, el flujo típico es: generás la key en el dashboard del proveedor, la necesitás en algún lado del código para que el cliente HTTP la use, y ahí está la bifurcación. Un camino lleva a un archivo de configuración que git ignora. El otro lleva a un string literal que git sí versiona.

La diferencia entre esos dos caminos no se nota el primer día. Se nota cuando:

  • alguien hace git log -p y encuentra la key en un commit de hace tres meses, aunque ya la borraste del archivo actual
  • un error no manejado en el cliente HTTP loguea el header Authorization completo en la consola o en un servicio de logging
  • el repo pasa a ser público, o alguien lo clona para colaborar y ahora tiene acceso a facturación ajena

Ninguno de estos escenarios requiere que alguien "hackee" nada. Requiere que la key haya estado en texto plano en un lugar que no controlás una vez que sale de tu máquina.

Qué dice la documentación oficial de Anthropic (y qué no dice)

La documentación de Anthropic sobre getting started es clara en un punto: la API key se pasa como header x-api-key en cada request, y se recomienda explícitamente no exponerla en código del lado del cliente ni en repositorios públicos. Ese es el límite de lo que la doc garantiza: te dice el mecanismo de autenticación y te avisa del riesgo obvio.

Lo que la documentación no dice —porque no es su trabajo— es cómo estructurar el proyecto para que esa key nunca llegue a un commit por accidente. Eso es una decisión de arquitectura del proyecto, no algo que resuelva un flag de la API. Ahí es donde entra el criterio propio, no la lectura literal de la doc.

La receta que la gente usa y por qué falla

El patrón que veo repetirse en proyectos personales y en ejemplos de tutoriales es este: crear un archivo .env en la raíz, poner ahí la key, y confiar en que "seguro está en el .gitignore default de Next.js". A veces sí. A veces el proyecto arrancó con un create-next-app viejo, o alguien renombró el archivo a .env.production sin revisar si esa variante también está ignorada.

El costo oculto no es el .env en sí. Es la falsa sensación de seguridad que da tener "un archivo separado" sin verificar que git efectivamente lo esté ignorando. Un contraejemplo típico: alguien copia .env a .env.backup para tener una referencia rápida, y ese archivo con sufijo distinto no matchea ningún patrón del .gitignore. La key queda ahí, versionada, con nombre de archivo que ni siquiera aparece sospechoso en un diff rápido.

Otro error común, más sutil: pasar la key como prop en un componente cliente de React. Si el componente corre en el browser, cualquier variable que empiece con NEXT_PUBLIC_ termina en el bundle de JavaScript que se descarga el navegador. Eso no es un bug de Next.js, es el comportamiento documentado: esas variables son públicas por diseño. Poner ahí una key de Claude es exponerla tan literalmente como pegarla en el código.

# .env.local (nunca se versiona, Next.js lo ignora por default)
ANTHROPIC_API_KEY=sk-ant-api03-xxxxx
OPENROUTER_API_KEY=sk-or-v1-xxxxx

# se lee del lado del servidor, nunca con prefijo NEXT_PUBLIC_
Enter fullscreen mode Exit fullscreen mode
// route.ts - server-side, la key nunca llega al browser
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
  throw new Error("Falta ANTHROPIC_API_KEY en las variables de entorno");
}
Enter fullscreen mode Exit fullscreen mode

Checklist antes de tocar cualquier API key de un proveedor LLM

Esta es la matriz que uso como criterio prudente, no como garantía absoluta de nada:

Situación Qué mirar primero Riesgo si se ignora
Proyecto nuevo con Next.js Confirmar que .gitignore incluye .env*.local explícitamente Key versionada desde el primer commit
Variable usada en componente cliente Verificar que NO tenga prefijo NEXT_PUBLIC_ Key visible en el bundle del navegador
Repo que va a ser público o compartido Correr `git log --all -p \ grep "sk-"` antes de publicar
Logs de error en servidor Revisar que el cliente HTTP no logue headers completos Authorization o x-api-key en texto plano en el log
Cline u otro agente con múltiples providers Confirmar que cada key vive en su variable separada, no en un string compartido Rotar una key rompe todos los proveedores a la vez
Key comprometida (sospecha o confirmación) Revocarla en el dashboard del proveedor antes de investigar la causa Ventana de uso indebido mientras se debuggea

El punto de rotación merece una aclaración: revocar primero, investigar después. No al revés. La ventana entre "sospecho que se filtró" y "la desactivé" es tiempo de uso que no controlás.

Qué NO se puede concluir de esto

Esta guía no reemplaza un escaneo de secretos automatizado en CI, y no es una auditoría de seguridad. Herramientas como git-secrets o los hooks de pre-commit que detectan patrones de keys agregan una capa que el ojo humano no cubre en cada commit. Tampoco tengo evidencia pública de incidentes específicos de filtración de keys de Claude o DeepSeek para citar acá: lo que hay es el mecanismo documentado de autenticación por header, y el comportamiento conocido de Next.js con las variables NEXT_PUBLIC_. El resto es criterio de arquitectura, no dato medido.

Si el proyecto ya tiene un caso de key expuesta en producción, esto no alcanza: ahí el paso es revocar, rotar y auditar accesos con las herramientas del proveedor, no leer un post.

flowchart LR
  A[Necesito una API key] --> B{¿Va a un componente cliente?}
  B -->|sí| C[No la pongas ahí. Usá un endpoint server-side]
  B -->|no| D[.env.local + process.env]
  D --> E{¿El repo se va a compartir?}
  E -->|sí| F[Revisá git log por patrones sk-]
  E -->|no| G[Confirmá .gitignore antes del primer commit]

Este mismo criterio de separar lo que corre en servidor de lo que llega al cliente lo toqué desde otro ángulo cuando escribí sobre cache y revalidación en Next.js: la frontera server/client no es solo una cuestión de performance, también es la frontera de qué secretos existen y cuáles no.

FAQ

¿Puedo usar la misma API key de Claude en desarrollo y producción?
Técnicamente sí, pero no es recomendable. Si la key de desarrollo se filtra en un repo o en un log de debug, el radio de daño incluye producción. Usar keys separadas por ambiente limita ese radio.

¿Alcanza con poner la key en .env sin el sufijo .local?
Depende de la configuración exacta del .gitignore del proyecto. El default de Next.js ignora .env*.local, pero un .env plano sin ese sufijo puede no estar cubierto. Conviene verificar el archivo, no asumir.

¿Qué diferencia hay entre manejar la key de Anthropic y la de OpenRouter?
El mecanismo cambia (headers distintos, formatos de key distintos), pero el criterio de manejo es idéntico: nunca en código versionado, nunca en variables públicas del cliente, siempre en variables de entorno server-side.

¿Cline expone las keys que uso con OpenRouter o Anthropic?
Cline las lee desde la configuración local de la extensión o desde variables de entorno del sistema, no las escribe en el código del proyecto. El riesgo aparece si el usuario copia esa key manualmente a un archivo del repo para "tenerla a mano".

¿Sirve rotar la key periódicamente aunque no haya sospecha de filtración?
Es una práctica prudente en cualquier sistema de credenciales, aunque no hay una regla universal de frecuencia. Lo que sí es concreto: si hay sospecha de filtración, la rotación no es periódica, es inmediata.

¿Un archivo .env.example sin valores reales es seguro de versionar?
Sí, siempre que contenga solo los nombres de las variables sin valores reales (ANTHROPIC_API_KEY=). Es una práctica común para documentar qué variables necesita el proyecto sin exponer nada.

Mi postura

No hay atajo legítimo para esto. La excusa de "solo para probar" es la misma excusa que se usa para dejar un console.log que después queda en producción, salvo que acá el costo no es un log molesto: es una key con acceso a facturación de un proveedor de LLM. Si estás armando un proyecto con múltiples providers —algo que toqué cuando hablé de monitorear el tráfico de agentes IA con Sniffnet— la disciplina de variables de entorno separadas por proveedor no es paranoia, es la única forma de que rotar una key no signifique romper las otras tres integraciones que dependen del mismo .env.

El próximo paso concreto, antes de escribir la próxima línea de código que llame a una API de LLM: abrí el .gitignore de tu proyecto y confirmá que efectivamente ignora los archivos de entorno que estás usando. No lo asumas.

Fuente original:


Este artículo fue publicado originalmente en juanchi.dev

Top comments (0)