
L'helper writeToFile di Consul Template ha aperto direttamente una destinazione fornita dall'operatore e ha seguito i componenti di percorso collegati, consentendo all'output generato di fuoriuscire dalla directory prevista e di sovrascrivere un file preesistente.
L'helper writeToFile di Consul Template apriva direttamente una destinazione fornita dall'operatore e seguiva i componenti di percorso linkati, consentendo all'output renderizzato di fuoriuscire dalla directory prevista e sovrascrivere un file preesistente.
Ho trovato questo problema durante la revisione di HashiCorp Consul Template, con una domanda diretta sulla sicurezza del filesystem in mente:
Se writeToFile riceve un percorso che sembra essere all'interno della directory prevista, verifica dove il filesystem scriverà effettivamente i dati?
In questo caso, la risposta è stata no.
L'helper di template writeToFile apriva direttamente il percorso finale fornito dall'utente tramite os.Create() o os.OpenFile().
Queste operazioni seguivano i collegamenti simbolici, le junction di directory e le equivalenti redirezioni del filesystem già presenti nel percorso di destinazione.
Ciò significava che la stringa del percorso poteva rimanere sotto la root prevista dall'operatore mentre la scrittura effettiva finiva altrove.
Nella mia prova di concetto controllata, una directory padre linkata ha reindirizzato l'output renderizzato al di fuori dell'albero previsto e ha causato la sovrascrittura di un file di destinazione preesistente.
Questo problema è diventato .
Bollettino HashiCorp: HCSEC-2026-20
Bollettino IBM: bollettino di sicurezza CVE-2026-14361
CVE: CVE-2026-14361
Corretto in: 0.42.1
photo0
la destinazione fornita dall'operatore appare all'interno della root prevista -> l'attaccante posiziona preventivamente un componente padre o finale linkato -> writeToFile apre il percorso direttamente -> il filesystem risolve la scrittura al di fuori della directory prevista -> il segreto renderizzato viene reindirizzato -> il target preesistente può essere sovrascritto
Consul Template renderizza dati da fonti come Consul e Vault.
L'helper writeToFile consente a un template di scrivere contenuto selezionato in un file locale separato applicando proprietario, gruppo e permessi richiesti.
La documentazione di HashiCorp mostra specificamente l'helper con materiale PKI:
private key -> writeToFile /my/path/to/cert.key
certificate authority -> writeToFile /my/path/to/cert.pem
certificate -> append to /my/path/to/cert.pem
Questo lo rende più di un semplice helper di output.
Il contenuto che attraversa questo confine può includere:
La domanda importante non era se writeToFile potesse creare un nome file richiesto.
La vera domanda era:
Il processo scrive nella posizione del filesystem prevista dall'operatore, o semplicemente in qualunque oggetto a cui il percorso si risolve al momento dell'apertura?
Nelle versioni vulnerabili, si fidava di quest'ultimo.
Gli helper di scrittura sono superfici di sicurezza ad alto valore perché passano dai dati dell'applicazione alla mutazione del filesystem.
I guasti interessanti spesso non sono la classica traversal ../.
Sono guasti di risoluzione:
Questo è particolarmente importante quando il processo viene eseguito con più privilegi sul filesystem rispetto all'attaccante.
Un attaccante locale a bassi privilegi potrebbe non essere in grado di sovrascrivere direttamente un file sensibile.
Ma se può influenzare un componente del percorso sotto una directory di scrittura prevista, un processo Consul Template più privilegiato potrebbe eseguire la scrittura al suo posto.
Questo era il confine su cui mi sono concentrato.
Non ho affrontato questo come una generica revisione di path traversal.
Il percorso fornito non richiedeva segmenti ...
Poteva rimanere lessicalmente all'interno della root prevista per tutto il tempo.
La domanda più forte era:
I componenti di destinazione linkati vengono rifiutati prima che il contenuto sensibile venga scritto?
Questa domanda è importante per entrambi:
Il secondo caso è particolarmente utile perché i log e la configurazione mostrano ancora un percorso dall'aspetto innocuo sotto la directory prevista.
Il filesystem lo risolve altrove.
La causa radice era la creazione diretta di file basata sul percorso senza validazione consapevole dei link.
Alla revisione testata, writeToFile() selezionava uno dei due percorsi di apertura.
La modalità append usava:
f, err = os.OpenFile(
path,
os.O_APPEND|os.O_WRONLY|os.O_CREATE,
perm,
)
La normale modalità di scrittura usava:
dirPath := filepath.Dir(path)
if _, err := os.Stat(dirPath); err != nil {
err := os.MkdirAll(dirPath, os.ModePerm)
if err != nil {
return "", err
}
}
f, err = os.Create(path)
Nessuno dei due percorsi rifiutava i componenti di destinazione linkati prima dell'apertura del file.
Questo è importante perché:
os.Create(path) segue le redirezioni esistenti del filesystem e tronca il file risoltoos.OpenFile(path, ...) segue i componenti di percorso linkati durante la modalità appendLa stessa assunzione basata sul percorso continuava dopo la scrittura.
Proprietà e permessi venivano applicati usando di nuovo il percorso:
err = os.Chown(path, uid, gid)
err = os.Chmod(path, perm)
Ciò significava che anche le operazioni sui metadati erano legate a un nome di percorso mutabile invece che al descrittore di file già aperto.
Perché l'attaccante può preparare la redirezione prima che writeToFile venga eseguito.
Nessuna race probabilistica è richiesta per l'attacco di base.
La sequenza è semplice:
writeToFile la apre direttamenteQuesta è l'intera vulnerabilità.
È vero che i sistemi operativi normalmente seguono i symlink durante le aperture di file basate sul percorso.
Questo non rende questo un comportamento applicativo sicuro.
La domanda di sicurezza non è:
"Go si è comportato come documentato?"
La vera domanda è:
Un helper che scrive dati sensibili renderizzati ha verificato che la destinazione risolta corrispondesse alla posizione prevista dall'operatore?
Nelle versioni vulnerabili, non lo ha fatto.
Questa distinzione è importante perché Consul Template può essere eseguito:
Seguire una redirezione del filesystem posizionata dall'attaccante in quel contesto crea un reale problema di privilegi e di confine di fiducia.
Ho costruito un riproduttore standalone attorno all'esatto comportamento di writeToFile al commit testato.
La configurazione controllata usava:
writeToFileIl flusso di riproduzione era:
Il comportamento osservato era:
writeToFile seguiva la redirezioneQuesto stabiliva entrambe le parti dell'affermazione:
Un symlink sul componente finale dimostrerebbe già un follow di link non sicuro.
Ma un componente padre linkato dimostra un punto operativo più forte:
Anche il target preesistente era importante.
Senza di esso, la PoC mostrerebbe solo una creazione di file inattesa.
Partendo da un file esistente e verificando la sua hash finale, la riproduzione ha dimostrato direttamente il comportamento di sovrascrittura.
Questo ha reso il risultato più concreto di una semplice affermazione basata sul codice sorgente.
Questo problema richiede influenza locale sul filesystem.
Un attaccante ha bisogno di accesso sufficiente per creare o modificare un symlink, una junction di directory o una equivalente redirezione nella o sotto la posizione di scrittura prevista.
Il processo Consul Template deve poi scrivere attraverso quel percorso.
L'impatto dipende fortemente dai privilegi del processo e dal contenuto renderizzato.
I risultati pratici includono:
Non si trattava di una scrittura arbitraria remota non autenticata da un'installazione predefinita.
Ma era un chiaro guasto del confine di fiducia locale con impatto significativo in deployment privilegiati o con filesystem condivisi.
HashiCorp ha classificato il problema come:
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N
Il punteggio base pubblicato è:
4.7 / Medium
Questo vettore riflette:
I bollettini ufficiali documentano anche esplicitamente che la scrittura reindirizzata può sovrascrivere un file preesistente.
Il punteggio è moderato perché lo sfruttamento dipende da condizioni locali di controllo del percorso, non perché l'effetto sul filesystem sia teorico.
Il bollettino HashiCorp elenca:
Affected: consul-template up to and including 0.42.0
Fixed: consul-template 0.42.1
La correzione è stata distribuita nella release 0.42.1 dell'8 luglio 2026.
La patch 0.42.1 ha indurito il percorso di scrittura su più livelli.
L'helper corretto usa os.Lstat() per ispezionare:
e rifiuta quei componenti quando sono link.
Questo chiude i casi di redirezione diretta del padre e di symlink sul file finale coperti dal report e dai test di regressione.
Sulle piattaforme Unix supportate, la destinazione viene aperta con O_NOFOLLOW.
Questo fa fallire l'apertura stessa se il componente finale diventa un symlink tra il pre-controllo e l'apertura.
Questo è importante perché un semplice pre-controllo da solo può creare un'altra finestra TOCTOU.
L'implementazione specifica per piattaforma è un no-op su Windows, dove O_NOFOLLOW non è disponibile attraverso lo stesso meccanismo.
La patch ha sostituito le operazioni di proprietà e modalità basate sul percorso con operazioni basate sul descrittore:
f.Chown(uid, gid)
f.Chmod(perm)
Questo vincola le modifiche ai metadati al file che è stato effettivamente aperto invece di risolvere nuovamente il percorso in seguito.
L'helper ora crea la directory padre solo quando il fallimento dello stat è genuinamente os.IsNotExist.
Altri errori, come i fallimenti di permessi, vengono restituiti invece di continuare nel percorso di scrittura.
La patch ha aggiunto test mirati per:
La discussione pubblica sulla patch documenta chiaramente una limitazione importante.
La nuova validazione controlla:
Non attraversa e rifiuta ogni componente antenato più in alto.
I maintainer hanno scelto questo confine perché writeToFile non ha una root sandbox configurata a cui ancorare un controllo completo di contenimento, e i sistemi operativi comuni possono includere link gestiti legittimi nei prefissi di percorso, come /var -> /private/var su macOS.
O_NOFOLLOW protegge anche solo il componente finale, non ogni directory antenata.
Questo non cambia lo stato della vulnerabilità riportata o della versione ufficiale corretta.
Chiarisce però l'esatta proprietà di sicurezza fornita dalla patch:
Questa distinzione vale la pena di essere preservata in un'analisi tecnica.
Ho segnalato questo problema privatamente al team di sicurezza di HashiCorp il 21 marzo 2026 come seconda scoperta indipendente su Consul Template.
Il report includeva:
L'email di follow-up originale non era presente nella coda dei report del team di sicurezza, probabilmente perché è stata intercettata da un filtro antispam della mailing list.
Dopo che ho re-inoltrato il report completo, HashiCorp ha contattato il team di ingegneria e lo ha investigato separatamente dal primo problema su Consul Template.
HashiCorp ha corretto la vulnerabilità in 0.42.1 e ha pubblicato HCSEC-2026-20 l'8 luglio 2026.
IBM ha pubblicato un bollettino di sicurezza corrispondente per la stessa CVE.
Entrambi i bollettini ufficiali hanno riconosciuto il report come:
Mohamed Abdelaal (0xmrma)
La lezione chiave è semplice:
una stringa di percorso non è la stessa cosa dell'oggetto del filesystem che nomina
Questa distinzione è importante ogni volta che codice privilegiato scrive percorsi influenzati dall'attaccante.
Controllare che una stringa inizi con una directory prevista non basta.
Anche un percorso pulito senza sequenze di traversal può risolversi altrove attraverso:
L'operazione sensibile deve essere legata a una destinazione la cui identità sia stata validata al confine giusto.
Questo problema rafforza anche una regola più ampia:
quando hai già un descrittore di file aperto, applica le operazioni sensibili alla sicurezza attraverso quel descrittore invece di risolvere di nuovo il percorso
Questo è esattamente il motivo per cui le modifiche a Chown e Chmod basate sul descrittore contano.
writeToFile è documentato per materiale sensibile come certificati e chiavi privateos.Create o os.OpenFileChown e Chmod basati sul percorso introducevano ulteriore fiducia in un percorso mutabile0.42.1 ha aggiunto controlli sui link, O_NOFOLLOW dove supportato, operazioni sui metadati basate sul descrittore e test di regressioneQuesta vulnerabilità non riguardava la traversal ../.
La stringa del percorso sembrava corretta.
La destinazione del filesystem non lo era.
Consul Template ha accettato il percorso previsto dall'operatore, ha seguito una redirezione posizionata dall'attaccante e ha scritto il contenuto renderizzato in un file diverso.
Questo è il motivo per cui è diventata CVE-2026-14361.
Corretta in consul-template 0.42.1.