
Le helper writeToFile de Consul Template ouvrait directement une destination fournie par l'opérateur et suivait les composants de chemins liés, permettant à la sortie rendue de s'échapper du répertoire prévu et d'écraser un fichier préexistant.
Le helper writeToFile de Consul Template ouvrait directement une destination fournie par l'opérateur et suivait les composants de chemin liés, permettant à la sortie rendue de s'échapper du répertoire prévu et d'écraser un fichier préexistant.
J'ai trouvé ce problème en examinant HashiCorp Consul Template, avec une question directe de sécurité du système de fichiers en tête :
Si writeToFile reçoit un chemin qui semble être à l'intérieur du répertoire prévu, vérifie-t-il où le système de fichiers écrira réellement les données ?
Dans ce cas, la réponse était non.
Le helper de template writeToFile ouvrait directement le chemin final fourni par l'utilisateur via os.Create() ou os.OpenFile().
Ces opérations suivaient les liens symboliques, les jonctions de répertoires et les redirections de système de fichiers équivalentes déjà présentes dans le chemin de destination.
Cela signifiait que la chaîne de chemin pouvait rester sous la racine prévue par l'opérateur pendant que l'écriture réelle aboutissait ailleurs.
Dans ma preuve de concept contrôlée, un répertoire parent lié redirigeait la sortie rendue hors de l'arborescence prévue et provoquait l'écrasement d'un fichier cible préexistant.
Ce problème est devenu CVE-2026-14361.
Bulletin HashiCorp : HCSEC-2026-20
Bulletin IBM : Bulletin de sécurité CVE-2026-14361
CVE : CVE-2026-14361
Corrigé dans : 0.42.1
photo0
destination fournie par l'opérateur apparaît dans la racine prévue -> l'attaquant pré-positionne un parent lié ou un composant final de chemin -> writeToFile ouvre le chemin directement -> le système de fichiers résout l'écriture hors du répertoire prévu -> le secret rendu est redirigé -> une cible préexistante peut être écrasée
Consul Template rend des données provenant de sources telles que Consul et Vault.
Le helper writeToFile permet à un modèle d'écrire un contenu sélectionné dans un fichier local séparé tout en appliquant un propriétaire, un groupe et un mode de permission demandés.
La documentation de HashiCorp démontre spécifiquement ce helper avec du matériel PKI :
clé privée -> writeToFile /my/path/to/cert.key
autorité de certification -> writeToFile /my/path/to/cert.pem
certificat -> ajout à /my/path/to/cert.pem
Cela en fait plus qu'un simple helper de sortie.
Le contenu qui franchit cette frontière peut inclure :
La question importante n'était pas de savoir si writeToFile pouvait créer un nom de fichier demandé.
La vraie question était :
Le processus écrit-il à l'emplacement du système de fichiers prévu par l'opérateur, ou simplement à l'objet vers lequel le chemin pointe au moment de l'ouverture ?
Dans les versions vulnérables, il se fiait à la seconde option.
Les helpers d'écriture sont des surfaces de sécurité à forte valeur car ils font passer des données d'application à une mutation du système de fichiers.
Les défaillances intéressantes ne sont souvent pas la traversée classique ../.
Ce sont des défaillances de résolution :
C'est particulièrement important lorsque le processus s'exécute avec plus de privilèges sur le système de fichiers que l'attaquant.
Un attaquant local peu privilégié peut ne pas être en mesure d'écraser directement un fichier sensible.
Mais s'il peut influencer un composant de chemin sous un répertoire d'écriture prévu, un processus Consul Template plus privilégié peut effectuer l'écriture à sa place.
C'est la frontière sur laquelle je me suis concentré.
Je n'ai pas abordé cela comme une revue générique de traversée de chemin.
Le chemin fourni n'avait pas besoin de segments ...
Il pouvait rester lexicalement à l'intérieur de la racine prévue tout du long.
La question la plus forte était :
Les composants de destination liés sont-ils rejetés avant que le contenu sensible ne soit écrit ?
Cette question concerne à la fois :
Le deuxième cas est particulièrement utile car les journaux et la configuration montrent toujours un chemin d'apparence innocente sous le répertoire attendu.
Le système de fichiers le résout ailleurs.
La cause racine était la création directe de fichier basée sur un chemin sans validation tenant compte des liens.
À la révision testée, writeToFile() sélectionnait l'un des deux chemins d'ouverture.
Le mode ajout utilisait :
f, err = os.OpenFile(
path,
os.O_APPEND|os.O_WRONLY|os.O_CREATE,
perm,
)
Le mode écriture normale utilisait :
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)
Aucun des deux chemins ne rejetait les composants de destination liés avant l'ouverture du fichier.
Cela importe parce que :
os.Create(path) suit les redirections existantes du système de fichiers et tronque le fichier résoluos.OpenFile(path, ...) suit les composants de chemin liés en mode ajoutLa même hypothèse basée sur le chemin se poursuivait après l'écriture.
La propriété et les permissions étaient appliquées en utilisant à nouveau le chemin :
err = os.Chown(path, uid, gid)
err = os.Chmod(path, perm)
Cela signifiait que les opérations de métadonnées étaient également liées à un nom de chemin mutable au lieu du descripteur de fichier déjà ouvert.
Parce que l'attaquant peut préparer la redirection avant que writeToFile ne s'exécute.
Aucune course probabiliste n'est requise pour l'attaque de base.
La séquence est simple :
writeToFile l'ouvre directementC'est toute la vulnérabilité.
Il est vrai que les systèmes d'exploitation suivent normalement les liens symboliques lors des ouvertures de fichiers basées sur un chemin.
Cela ne fait pas de ce comportement un comportement sûr pour une application.
La question de sécurité n'est pas :
« Go s'est-il comporté comme documenté ? »
La vraie question est :
Le helper qui écrivait des données sensibles rendues a-t-il vérifié que la destination résolue correspondait à l'emplacement prévu par l'opérateur ?
Dans les versions vulnérables, ce n'était pas le cas.
Cette distinction importe car Consul Template peut s'exécuter :
Suivre une redirection du système de fichiers positionnée par l'attaquant dans ce contexte crée un véritable problème de privilèges et de frontière de confiance.
J'ai construit un reproducteur autonome autour du comportement exact de writeToFile au commit testé.
La configuration contrôlée utilisait :
writeToFileLe flux de reproduction était :
Le comportement observé était :
writeToFile suivait la redirectionCela établissait les deux parties de l'affirmation :
Un lien symbolique en composant final démontrerait déjà le suivi dangereux des liens.
Mais un composant parent lié prouve un point opérationnel plus fort :
La cible préexistante importait aussi.
Sans elle, la PoC ne montrerait qu'une création de fichier inattendue.
En commençant avec un fichier existant et en vérifiant son empreinte finale, la reproduction prouvait directement le comportement d'écrasement.
Cela rendait le résultat plus concret qu'une affirmation basée uniquement sur le code source.
Ce problème nécessite une influence locale sur le système de fichiers.
Un attaquant doit avoir un accès suffisant pour créer ou modifier un lien symbolique, une jonction de répertoires ou une redirection équivalente dans ou sous l'emplacement d'écriture prévu.
Le processus Consul Template doit ensuite écrire à travers ce chemin.
L'impact dépend fortement des privilèges du processus et du contenu rendu.
Les conséquences pratiques incluent :
Ce n'était pas une écriture arbitraire à distance non authentifiée depuis une installation par défaut.
Mais c'était une défaillance claire de frontière de confiance locale avec un impact significatif dans les déploiements privilégiés ou à système de fichiers partagé.
HashiCorp a classé le problème comme :
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N
Le score de base publié est :
4.7 / Moyen
Ce vecteur reflète :
Les bulletins officiels documentent également explicitement que l'écriture redirigée peut écraser un fichier préexistant.
Le score est modéré car l'exploitation dépend de conditions locales de contrôle du chemin, pas parce que l'effet sur le système de fichiers est théorique.
Le bulletin HashiCorp liste :
Affecté : consul-template jusqu'à 0.42.0 inclus
Corrigé : consul-template 0.42.1
Le correctif a été livré dans la version 0.42.1 le 8 juillet 2026.
Le correctif 0.42.1 a durci le chemin d'écriture à plusieurs niveaux.
Le helper corrigé utilise os.Lstat() pour inspecter :
et rejette ces composants lorsqu'ils sont des liens.
Cela ferme les cas de redirection directe par le parent et de lien symbolique du fichier final couverts par le rapport et les tests de régression.
Sur les plateformes Unix prises en charge, la destination est ouverte avec O_NOFOLLOW.
Cela fait échouer l'ouverture elle-même si le composant final devient un lien symbolique entre la pré-vérification et l'ouverture.
C'est important car une simple pré-vérification peut créer une autre fenêtre TOCTOU.
L'implémentation spécifique à la plateforme est un no-op sur Windows, où O_NOFOLLOW n'est pas disponible via le même mécanisme.
Le correctif a remplacé les opérations de propriété et de mode basées sur le chemin par des opérations basées sur le descripteur :
f.Chown(uid, gid)
f.Chmod(perm)
Cela lie les changements de métadonnées au fichier réellement ouvert au lieu de résoudre à nouveau le chemin plus tard.
Le helper ne crée désormais le répertoire parent que lorsque l'échec de stat est réellement os.IsNotExist.
Les autres erreurs, telles que les échecs de permission, sont renvoyées au lieu de poursuivre dans le chemin d'écriture.
Le correctif a ajouté des tests ciblés pour :
La discussion publique sur le correctif documente clairement une limite importante.
La nouvelle validation vérifie :
Elle ne parcourt pas et ne rejette pas chaque composant ancêtre supérieur.
Les mainteneurs ont choisi cette limite car writeToFile n'a pas de racine de bac à sable configurée pour ancrer une vérification complète de confinement, et les systèmes d'exploitation courants peuvent inclure des liens gérés légitimes dans les préfixes de chemin, comme /var -> /private/var sur macOS.
O_NOFOLLOW protège également le composant final, pas chaque répertoire ancêtre.
Cela ne change pas le statut de la vulnérabilité signalée ni la version officielle corrigée.
Cela clarifie la propriété de sécurité exacte apportée par le correctif :
Cette distinction mérite d'être préservée dans une analyse technique.
J'ai signalé ce problème en privé à l'équipe sécurité de HashiCorp le 21 mars 2026 en tant que deuxième découverte indépendante sur Consul Template.
Le rapport incluait :
L'e-mail de suivi original n'était pas présent dans la file de rapports de l'équipe sécurité, probablement parce qu'il avait été intercepté par un filtre anti-spam de liste de diffusion.
Après avoir renvoyé le rapport complet, HashiCorp a pris contact avec l'équipe d'ingénierie et l'a examiné séparément du premier problème Consul Template.
HashiCorp a corrigé la vulnérabilité dans 0.42.1 et a publié HCSEC-2026-20 le 8 juillet 2026.
IBM a publié un bulletin de sécurité correspondant pour la même CVE.
Les deux bulletins officiels ont reconnu le rapport comme :
Mohamed Abdelaal (0xmrma)
La leçon clé est simple :
une chaîne de chemin n'est pas la même chose que l'objet du système de fichiers qu'elle nomme
Cette distinction importe chaque fois qu'un code privilégié écrit des chemins influencés par un attaquant.
Vérifier qu'une chaîne commence par un répertoire prévu ne suffit pas.
Même un chemin propre sans séquences de traversée peut être résolu ailleurs via :
L'opération sensible doit être liée à une destination dont l'identité a été validée à la bonne frontière.
Ce problème renforce également une règle plus large :
lorsque vous avez déjà un descripteur de fichier ouvert, appliquez les opérations sensibles pour la sécurité via ce descripteur au lieu de résoudre à nouveau le chemin
C'est exactement pourquoi les modifications Chown et Chmod basées sur le descripteur importent.
writeToFile est documenté pour des matériaux sensibles tels que les certificats et les clés privéesos.Create ou os.OpenFileChown et Chmod basés sur le chemin introduisaient une confiance supplémentaire dans un chemin mutable0.42.1 a ajouté des vérifications de liens, O_NOFOLLOW là où c'est pris en charge, des opérations de métadonnées basées sur le descripteur et des tests de régressionCette vulnérabilité ne concernait pas la traversée ../.
La chaîne de chemin semblait correcte.
La destination du système de fichiers ne l'était pas.
Consul Template a accepté le chemin prévu par l'opérateur, suivi une redirection positionnée par l'attaquant et écrit le contenu rendu dans un fichier différent.
C'est pourquoi cela est devenu CVE-2026-14361.
Corrigé dans consul-template 0.42.1.