Reports
MEDIA[CONFIGURACIÓN]#3630605

Kiro IDE guardaba los tokens de acceso de sus usuarios en un fichero legible por cualquiera (0644)

Kiro IDE escribía el access token y el refresh token en ~/.aws/sso/cache/kiro-auth-token.json con permisos 0644, así que cualquier proceso o usuario local podía leerlos y suplantar a la víctima ante la API de CodeWhisperer/Q Developer.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

Kiro IDE, de AWS, guardaba las credenciales de sesión del usuario en disco sin restringir quién podía leerlas. En la versión 0.11.107, al iniciar sesión (con GitHub o con AWS Builder ID), el IDE escribía un JSON con el access token y el refresh token en:

~/.aws/sso/cache/kiro-auth-token.json

El fichero quedaba con permisos 0644 (-rw-r--r--): legible por cualquier usuario del sistema y por cualquier proceso local. Es un caso de permisos por defecto incorrectos (CWE-276), registrado como CVE-2026-11931, con severidad media.

Lo llamativo es el contraste con el resto del ecosistema de AWS:

  • La AWS CLI guarda sus tokens SSO en ese mismo directorio con permisos 0600.
  • El propio Kiro ya usaba el llavero del sistema (macOS Keychain, a través de secretStorage de VS Code) para las credenciales OAuth de MCP. El patrón seguro existía en el código, pero no se aplicaba a este token.

La causa, según el investigador, está en la clase TokenStorage del extension.js minificado (línea 504375 en la build 672afb51e5336b149eb9fc381dd6db6908edbc61): llama a fs.writeFileSync() sin el parámetro mode. Node.js crea entonces el fichero con 0666, que la umask habitual (022) deja en 0644. Después no se aplicaba ningún chmod.

El investigador indicó que era uno de seis fallos que reportaba en Kiro IDE; los otros cubrían escalada de privilegios de extensión a agente (CWE-862), inyección de órdenes en hooks (CWE-78), un salto del modo Autopilot forzado mediante askAgent (CWE-862), la sobrescritura de la configuración MCP del espacio de trabajo (CWE-78/CWE-862) y una redirección del token mediante enlaces simbólicos (CWE-59).

Pasos de reproducción

  1. Iniciar sesión en Kiro de la forma habitual (con GitHub o con AWS Builder ID).
  1. Comprobar los permisos de los ficheros de la caché SSO (la sintaxis de stat es la de macOS):
stat -f "%Op %Sp %N" ~/.aws/sso/cache/*.json

Los ficheros de la AWS CLI aparecen con 0600; el de Kiro, con 0644:

100600 -rw------- ~/.aws/sso/cache/REDACTED_HASH_1.json  (AWS CLI - correct)
100600 -rw------- ~/.aws/sso/cache/REDACTED_HASH_2.json  (AWS CLI - correct)
100644 -rw-r--r-- ~/.aws/sso/cache/kiro-auth-token.json  (Kiro - world-readable)
  1. Leer el fichero y comprobar que las credenciales están en claro:
cat ~/.aws/sso/cache/kiro-auth-token.json

{
  "accessToken": "[REDACTADO]",
  "refreshToken": "[REDACTADO]",
  "profileArn": "arn:aws:codewhisperer:us-east-1:[REDACTADO]:profile/[REDACTADO]",
  "expiresAt": "2026-03-26T18:44:44.275Z",
  "authMethod": "social",
  "provider": "Github"
}
  1. Confirmar que el origen es el comportamiento por defecto de Node.js al escribir un fichero sin indicar mode:
node -e "const fs=require('fs'); const p='/tmp/test.json'; fs.writeFileSync(p,'test'); console.log((fs.statSync(p).mode & 0o777).toString(8)); fs.unlinkSync(p);"
# Output: 644

Impacto

Quien leyera el fichero se llevaba unos tokens de portador que permiten actuar como la víctima ante la API de CodeWhisperer / Q Developer. El investigador enumera las operaciones de CodeWhispererRuntimeClient accesibles con ellos:

CreateSession, SendMessage, GenerateCompletions, ListAvailableModels,
GetUsageLimits, CreateSubscriptionToken, CreateArtifactUploadUrl

Con eso un atacante podía:

  • Usar el chat agéntico completo y la generación de código haciéndose pasar por la víctima.
  • Gastar sus créditos y agotar los límites del plan gratuito.
  • Acceder al contexto de código de las sesiones de la víctima.

El vector más realista que plantea el informe es una extensión maliciosa o con nombre suplantado (typosquatting) para Kiro o VS Code: las extensiones se ejecutan con todos los permisos del usuario, así que podían leer el fichero y enviarlo fuera. El investigador añade que el host de extensiones de Kiro se ejecuta con los entitlements allow-unsigned-executable-memory y disable-library-validation. Los permisos 0644 exponen además el fichero a cualquier otro usuario o proceso de la misma máquina.

Remediación

El reporte figura como resuelto y se le asignó el CVE-2026-11931. El original no detalla el cambio aplicado por AWS. El investigador propuso dos opciones:

  • Pasar { mode: 0o600 } a fs.writeFileSync() al crear el fichero de tokens.
  • O bien guardar los tokens con secretStorage de VS Code (llavero del sistema), como Kiro ya hacía con las credenciales OAuth de MCP.

Qué aprender de este caso

  • Si auditas una herramienta de escritorio o una extensión, revisa los permisos de lo que deja en ~/.aws, ~/.config o cachés parecidas tras iniciar sesión: un stat comparando con los ficheros de otras herramientas (aquí la AWS CLI con 0600) delata enseguida al que se sale de la norma.
  • En Node.js, fs.writeFileSync() sin mode hereda la umask y suele acabar en 0644. Busca en el código llamadas que escriban tokens o secretos sin { mode: 0o600 }; y recuerda que mode solo se aplica al crear el fichero, así que si ya existía con otros permisos conviene un chmod explícito.
  • Cuando una misma aplicación guarda unos secretos en el llavero del sistema y otros en ficheros planos, el camino de los ficheros es el primero que merece revisarse: es donde suele faltar la protección.
  • Un refresh token en disco tiene más valor para un atacante que un access token de vida corta: si no se puede llevar al llavero del sistema, que al menos solo lo pueda leer el usuario propietario.