
Consul Template ने टेम्पलेट मूल्यांकन के दौरान सत्यापित किया कि symlink किस ओर इंगित कर रहा था, लेकिन उसके बाद की dependency fetch ने मूल पथ को पढ़ा। उन कार्यों के बीच लिंक को पुनः लक्षित करने से in-sandbox फ़ाइल संदर्भ out-of-sandbox फ़ाइल प्रकटीकरण में बदल गया।
Consul Template ने जाँच की कि टेम्पलेट मूल्यांकन के दौरान एक सिमलिंक किस ओर इंगित कर रहा था, लेकिन उसकी बाद की निर्भरता फ़ेच ने मूल पथ को पढ़ा। उन ऑपरेशनों के बीच लिंक को पुनः लक्षित करने से सैंडबॉक्स के अंदर की फ़ाइल का संदर्भ, सैंडबॉक्स के बाहर की फ़ाइल के प्रकटीकरण में बदल गया।
मुझे यह समस्या HashiCorp Consul Template की समीक्षा करते समय मिली, जब मेरे मन में एक बहुत ही विशिष्ट सुरक्षा प्रश्न था:
यदि sandbox_path टेम्पलेट मूल्यांकन के दौरान किसी सिमलिंक को वैलिडेट करता है, तो क्या बाद में फ़ाइल पढ़ना उसी वैलिडेट किए गए लक्ष्य से बंधा रहता है?
इस मामले में, उत्तर नहीं था।
file टेम्पलेट हेल्पर ने टेम्पलेट मूल्यांकन के दौरान पथ को रिज़ॉल्व किया और कॉन्फ़िगर किए गए सैंडबॉक्स को लागू किया। लेकिन उस जाँच के बाद, उसने मूल कच्चे पथ का उपयोग करके एक फ़ाइल निर्भरता बनाई।
वह निर्भरता बाद में फ़ेच की गई।
यदि कोई हमलावर वैलिडेशन और निर्भरता फ़ेच के बीच के अंतराल में सिमलिंक को पुनः लक्षित कर देता, तो Consul Template सैंडबॉक्स से बाहर की फ़ाइल पढ़ सकता था। यदि अगले रेंडर से पहले लिंक को पुनर्स्थापित कर दिया जाता, तो सैंडबॉक्स वैलिडेशन फिर से पास हो जाता और कैश की गई बाहरी सामग्री फिर भी रेंडर हो जाती।
वही समस्या CVE-2026-5061 बन गई।
HashiCorp बुलेटिन: HCSEC-2026-12
IBM बुलेटिन: CVE-2026-5061 सुरक्षा बुलेटिन
0.42.0photo0
attacker-controlled in-sandbox symlink -> sandbox validation resolves to safe target -> dependency stores original raw path -> attacker retargets link outside sandbox -> dependency fetch reads external file -> attacker restores safe link -> next validation passes -> cached external content is rendered
Consul Template Consul और Vault डेटा के लिए एक टेम्पलेट रेंडरिंग टूल है।
यह लगातार चल सकता है, परिवर्तनों के लिए निर्भरताओं पर नज़र रख सकता है, और एप्लिकेशन द्वारा उपभोग के लिए डेटा को फ़ाइलों या पर्यावरण चर में रेंडर कर सकता है।
file टेम्पलेट हेल्पर एक स्थानीय फ़ाइल पढ़ता है और उसकी सामग्री को रेंडर किए गए आउटपुट में डालता है।
चूँकि स्थानीय फ़ाइल पठन प्रक्रिया-पठनीय गोपनीय डेटा उजागर कर सकता है, Consul Template इस हेल्पर के लिए sandbox_path को एक सीमा के रूप में प्रदान करता है।
प्रलेखित सुरक्षा गुण सीधा है:
file को दिए गए पथ कॉन्फ़िगर किए गए सैंडबॉक्स के अंदर होने चाहिएयह sandbox_path को एक वास्तविक सुरक्षा सीमा बनाता है।
महत्वपूर्ण प्रश्न यह नहीं था कि क्या पथ सैंडबॉक्स के अंतर्गत दिख रहा था।
असली प्रश्न था:
क्या जो फ़ाइल पढ़ी जाती है, वह वही फ़ाइल रहती है जिसने सैंडबॉक्स वैलिडेशन पास किया था?
कमजोर संस्करणों में, ऐसा नहीं था।
फाइलसिस्टम सैंडबॉक्स अक्सर पथ वैलिडेशन और फ़ाइल एक्सेस के बीच के अंतराल पर विफल होते हैं।
सामान्य पैटर्न यह है:
वह धारणा असुरक्षित है जब कोई हमलावर दोनों ऑपरेशनों के बीच सिमलिंक या समकक्ष फाइलसिस्टम पुनर्निर्देशन को संशोधित कर सकता है।
Consul Template ने इस सतह को विशेष रूप से दिलचस्प बना दिया क्योंकि टेम्पलेट मूल्यांकन और निर्भरता फ़ेच अलग-अलग चरण थे।
उस अलगाव ने सही सुरक्षा प्रश्न निर्मित किया:
क्या निर्भरता फ़ेच वैलिडेट किए गए लक्ष्य से बंधा है, या क्या यह हमलावर-नियंत्रित पथ को फिर से रिज़ॉल्व करता है?
मैंने इसी सीमा पर ध्यान केंद्रित किया।
मूल कारण जाँच-के-समय से उपयोग-के-समय (time-of-check to time-of-use) के बीच का बेमेल था:
template/funcs.go में सैंडबॉक्स वैलिडेशनdependency/file.go में बाद में निर्भरता पठनपरीक्षण किए गए संशोधन पर, fileFunc() ने यह किया:
normalized := strings.TrimSpace(s)
err := pathInSandbox(sandboxPath, normalized)
if err != nil {
return "", err
}
d, err := dep.NewFileQuery(s)
वैलिडेशन हेल्पर ने समावेशन की जाँच करने से पहले सिमलिंक को सही ढंग से रिज़ॉल्व किया:
sandboxResolved, err := filepath.EvalSymlinks(filepath.Clean(sandbox))
targetResolved, err := filepath.EvalSymlinks(filepath.Clean(path))
rel, err := filepath.Rel(sandboxResolved, targetResolved)
if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
return fmt.Errorf("'%s' is outside of sandbox", path)
}
अतः सैंडबॉक्स जाँच ने स्वयं रिज़ॉल्व किए गए लक्ष्य को समझा।
लेकिन वह रिज़ॉल्व किया गया लक्ष्य छोड़ दिया गया।
NewFileQuery() ने इसके बजाय मूल स्ट्रिंग संग्रहीत की:
return &FileQuery{
stopCh: make(chan struct{}, 1),
path: s,
}, nil
फिर बाद की निर्भरता फ़ेच ने उस पथ को फिर से पढ़ा:
data, err := os.ReadFile(d.path)
यही पूरी कमजोरी है।
कोड ने एक फाइलसिस्टम रिज़ॉल्यूशन की जाँच की, फिर बाद में दूसरे का उपयोग किया।
क्योंकि एक सिमलिंक परिवर्तनशील (mutable) है।
हमलावर को सैंडबॉक्स से बाहर के लक्ष्य को सीधे pathInSandbox() से पास कराने की आवश्यकता नहीं है।
उन्हें केवल यह बदलना होता है कि वैलिडेशन के बाद लेकिन Fetch() द्वारा पठन करने से पहले पहले से स्वीकृत कच्चा पथ किस ओर रिज़ॉल्व होता है।
अनुक्रम यह है:
pathInSandbox() के दौरान लिंक एक सुरक्षित फ़ाइल की ओर रिज़ॉल्व होता हैFileQuery कच्चे लिंक पथ को दर्ज करता हैos.ReadFile(d.path) लिंक को फिर से रिज़ॉल्व करता हैवह अंतिम चरण महत्वपूर्ण है।
सुरक्षित लिंक को पुनर्स्थापित करने से पहले से फ़ेच किया गया गोपनीय डेटा निर्भरता कैश से नहीं हटा।
महत्वपूर्ण अंतर एक स्पष्ट सुरक्षा नियंत्रण का बायपास है।
यह केवल यह नहीं था:
"फ़ाइल तब बदल गई जब Consul Template उसे देख रहा था"
परिवर्तनों के लिए फ़ाइलों पर नज़र रखना अपेक्षित व्यवहार है।
असली मुद्दा था:
एक पथ जिसने प्रलेखित सैंडबॉक्स प्रतिबंध को पार किया था, बाद में उस सैंडबॉक्स के बाहर की फ़ाइल को पढ़ने के लिए उपयोग किया जा सकता था
यह प्रत्यक्ष विश्वास-सीमा (trust-boundary) विफलता है।
एप्लिकेशन पहले ही एक सुरक्षा निर्णय ले चुका था:
लेकिन बाद की फ़ेच उस लक्ष्य से बंधी नहीं थी जिसने उस निर्णय को उचित ठहराया था।
इसी ने सामान्य फाइलसिस्टम परिवर्तनशीलता को एक कमजोरी में बदल दिया।
मैंने सटीक मूल्यांकन और निर्भरता-फ़ेच अनुक्रम के आसपास एक स्टैंडअलोन रिप्रोड्यूसर बनाया।
नियंत्रित सेटअप में उपयोग किया गया:
पुनरुत्पादन प्रवाह यह था:
file हेल्पर का मूल्यांकन करें ताकि सैंडबॉक्स वैलिडेशन सफल हो और कच्चा पथ एक निर्भरता के रूप में पंजीकृत हो।os.ReadFile(d.path) को पुनर्निर्देशित लिंक के माध्यम से पढ़ने दें।अवलोकित व्यवहार यह था:
वह हैश तुलना मायने रखती थी।
इसने साबित किया कि अंतिम रेंडर किया गया मान पुरानी सुरक्षित सामग्री, फ़ाइलनाम से उत्पन्न कोई कृत्रिम परिणाम, या त्रुटि-पथ का दुष्प्रभाव नहीं था।
यह सैंडबॉक्स से बाहर की फ़ाइल की बाइट-सटीक सामग्री थी।
TOCTOU मुद्दे के लिए सबसे मजबूत प्रमाण को समयरेखा को नियंत्रित करना चाहिए।
केवल यह दिखाना कि एक सिमलिंक सैंडबॉक्स के बाहर इंगित कर सकता है, अधिक कमजोर होता, क्योंकि pathInSandbox() पहले से ही किसी बाहरी लक्ष्य को अस्वीकार कर देता था जब वह उसे देखता था।
सुरक्षा दावा इन सभी अवस्थाओं को क्रम से सिद्ध करने पर निर्भर था:
इसीलिए रिप्रोड्यूसर ने टेम्पलेट वैलिडेशन, निर्भरता फ़ेच, लिंक पुनर्स्थापना, और अगले रेंडर को स्पष्ट रूप से अलग किया।
PoC यादृच्छिक समय या बार-बार अनुमान लगाने पर निर्भर नहीं था।
उसने कमजोर जीवनचक्र को निर्धारणात्मक रूप से संचालित किया।
इससे मूल कारण और प्रभाव का बचाव करना बहुत आसान हो गया।
इस मुद्दे के लिए स्थानीय फाइलसिस्टम पर प्रभाव की आवश्यकता होती है।
एक हमलावर को कमजोर समय-खिड़की के दौरान प्रासंगिक सिमलिंक या समकक्ष लिंक किए गए पथ को बनाने, बदलने, या पुनः लक्षित करने के लिए पर्याप्त पहुँच की आवश्यकता होती है।
Consul Template प्रक्रिया के पास यह भी होना चाहिए:
वे आवश्यकताएँ मायने रखती हैं।
यह किसी डिफ़ॉल्ट तैनाती से बिना प्रमाणीकरण के दूरस्थ मनमाना फ़ाइल पठन नहीं था।
लेकिन प्रभावित स्थानीय विश्वास मॉडल के भीतर, प्रभाव सार्थक था:
sandbox_path प्रतिबंध का बायपासजोखिम तब बढ़ जाता है जब प्रक्रिया संवेदनशील क्रेडेंशियल्स, सेवा कॉन्फ़िगरेशन, टोकन, या निजी कुंजियों तक पहुँच के साथ चलती है।
HashiCorp ने इस मुद्दे को इस प्रकार वर्गीकृत किया:
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N
प्रकाशित आधार स्कोर है:
4.7 / Medium
वह स्कोरिंग वास्तविक बाधाओं को दर्शाती है:
यह एक उचित वर्गीकरण है।
मुद्दा हमलावर पूर्वापेक्षाओं में संकीर्ण है, लेकिन सैंडबॉक्स बायपास और उससे उत्पन्न फ़ाइल प्रकटीकरण दोनों ठोस हैं।
HashiCorp बुलेटिन सूचीबद्ध करता है:
Affected: consul-template up to 0.41.4
Fixed: consul-template 0.42.0
फिक्स 0.42.0 रिलीज़ में 15 अप्रैल, 2026 को जारी किया गया।
फिक्स छोटा था और उसने सीधे टूटी हुई बाइंडिंग को संबोधित किया।
रिज़ॉल्व किए गए लक्ष्य को वैलिडेट करने और फिर कच्चे इनपुट से निर्भरता बनाने के बजाय, पैच किया गया कोड रिज़ॉल्व किए गए पथ को लौटाता है और उस पथ को NewFileQuery() को देता है:
resolvedPath, err := resolveSandboxedPath(
sandboxPath,
strings.TrimSpace(s),
)
if err != nil {
return "", err
}
d, err := dep.NewFileQuery(resolvedPath)
सुरक्षा गुण इससे बदल गया:
इस ओर:
यह रिपोर्ट किए गए सिमलिंक-पुनःलक्ष्यीकरण मार्ग को बंद कर देता है क्योंकि मूल लिंक को बदलने से निर्भरता द्वारा संग्रहीत पथ अब नहीं बदलता।
पैच ने सटीक अनुक्रम को कवर करने वाला एक केंद्रित रिग्रेशन परीक्षण भी जोड़ा:
इस बग के लिए आप इसी तरह का सुधार चाहते हैं:
मैंने इस मुद्दे को 20 मार्च, 2026 को निजी रूप से HashiCorp Security को रिपोर्ट किया।
रिपोर्ट में शामिल था:
HashiCorp ने 0.42.0 में मुद्दे को ठीक किया और 12 मई, 2026 को HCSEC-2026-12 प्रकाशित किया।
IBM ने उसी CVE के लिए एक संगत सुरक्षा बुलेटिन प्रकाशित किया।
दोनों आधिकारिक बुलेटिनों ने रिपोर्ट को इस प्रकार स्वीकार किया:
Mohamed Abdelaal (0xmrma)
मुख्य सबक सरल है:
किसी पथ को वैलिडेट करना पर्याप्त नहीं है यदि बाद का फ़ाइल ऑपरेशन उस पथ को किसी भिन्न वस्तु की ओर रिज़ॉल्व कर सकता है
वह नियम Consul Template से कहीं आगे लागू होता है।
यह हर जगह मायने रखता है जहाँ कोड यह करता है:
गहरा सुरक्षा गुण यह नहीं है:
"पथ स्ट्रिंग एक बार सुरक्षित दिखी थी"
यह है:
संवेदनशील ऑपरेशन द्वारा उपयोग की जाने वाली वस्तु वही होनी चाहिए जिसने वैलिडेशन पास किया हो
इस मामले में, Consul Template ने एक रिज़ॉल्यूशन को वैलिडेट किया और दूसरे को फ़ेच किया।
वह अंतराल पर्याप्त था।
sandbox_path एक स्पष्ट स्थानीय-फ़ाइल सुरक्षा सीमा थीpathInSandbox() ने सिमलिंक लक्ष्य को सही ढंग से रिज़ॉल्व और वैलिडेट कियाFileQuery ने मूल हमलावर-प्रभावित पथ बनाए रखाos.ReadFile के माध्यम से उस पथ को फिर से रिज़ॉल्व किया0.42.0 ने निर्भरता को रिज़ॉल्व किए गए, वैलिडेट किए गए पथ से बाँधकर बग को ठीक कियायह कमजोरी स्ट्रिंग-उपसर्ग जाँच को बायपास करने के बारे में नहीं थी।
यह समय और पहचान के बारे में थी।
Consul Template ने जाँचा कि टेम्पलेट मूल्यांकन के दौरान लिंक कहाँ इंगित कर रहा था। निर्भरता फ़ेच ने बाद में फाइलसिस्टम से वही प्रश्न फिर से पूछा। एक हमलावर उन दो क्षणों के बीच उत्तर बदल सकता था।
इसीलिए यह CVE-2026-5061 बन गई।
consul-template 0.42.0 में ठीक की गई।